mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	deprecate cAdvisor json metrics collected by Kubelet
- remove unused code for cadvisor json metrics collected Signed-off-by: pacoxu <paco.xu@daocloud.io>
This commit is contained in:
		| @@ -167,8 +167,6 @@ type KubeletFlags struct { | ||||
| 	// This flag, if set, instructs the kubelet to keep volumes from terminated pods mounted to the node. | ||||
| 	// This can be useful for debugging volume related issues. | ||||
| 	KeepTerminatedPodVolumes bool | ||||
| 	// EnableCAdvisorJSONEndpoints enables some cAdvisor endpoints that will be removed in future versions | ||||
| 	EnableCAdvisorJSONEndpoints bool | ||||
| } | ||||
|  | ||||
| // NewKubeletFlags will create a new KubeletFlags with default values | ||||
| @@ -181,20 +179,19 @@ func NewKubeletFlags() *KubeletFlags { | ||||
| 	} | ||||
|  | ||||
| 	return &KubeletFlags{ | ||||
| 		ContainerRuntimeOptions:     *NewContainerRuntimeOptions(), | ||||
| 		CertDirectory:               "/var/lib/kubelet/pki", | ||||
| 		RootDirectory:               defaultRootDir, | ||||
| 		MasterServiceNamespace:      metav1.NamespaceDefault, | ||||
| 		MaxContainerCount:           -1, | ||||
| 		MaxPerPodContainerCount:     1, | ||||
| 		MinimumGCAge:                metav1.Duration{Duration: 0}, | ||||
| 		NonMasqueradeCIDR:           "10.0.0.0/8", | ||||
| 		RegisterSchedulable:         true, | ||||
| 		RemoteRuntimeEndpoint:       remoteRuntimeEndpoint, | ||||
| 		NodeLabels:                  make(map[string]string), | ||||
| 		RegisterNode:                true, | ||||
| 		SeccompProfileRoot:          filepath.Join(defaultRootDir, "seccomp"), | ||||
| 		EnableCAdvisorJSONEndpoints: false, | ||||
| 		ContainerRuntimeOptions: *NewContainerRuntimeOptions(), | ||||
| 		CertDirectory:           "/var/lib/kubelet/pki", | ||||
| 		RootDirectory:           defaultRootDir, | ||||
| 		MasterServiceNamespace:  metav1.NamespaceDefault, | ||||
| 		MaxContainerCount:       -1, | ||||
| 		MaxPerPodContainerCount: 1, | ||||
| 		MinimumGCAge:            metav1.Duration{Duration: 0}, | ||||
| 		NonMasqueradeCIDR:       "10.0.0.0/8", | ||||
| 		RegisterSchedulable:     true, | ||||
| 		RemoteRuntimeEndpoint:   remoteRuntimeEndpoint, | ||||
| 		NodeLabels:              make(map[string]string), | ||||
| 		RegisterNode:            true, | ||||
| 		SeccompProfileRoot:      filepath.Join(defaultRootDir, "seccomp"), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -368,9 +365,6 @@ func (f *KubeletFlags) AddFlags(mainfs *pflag.FlagSet) { | ||||
| 	fs.MarkDeprecated("non-masquerade-cidr", "will be removed in a future version") | ||||
| 	fs.BoolVar(&f.KeepTerminatedPodVolumes, "keep-terminated-pod-volumes", f.KeepTerminatedPodVolumes, "Keep terminated pod volumes mounted to the node after the pod terminates.  Can be useful for debugging volume related issues.") | ||||
| 	fs.MarkDeprecated("keep-terminated-pod-volumes", "will be removed in a future version") | ||||
| 	fs.BoolVar(&f.EnableCAdvisorJSONEndpoints, "enable-cadvisor-json-endpoints", f.EnableCAdvisorJSONEndpoints, "Enable cAdvisor json /spec and /stats/* endpoints. This flag has no effect on the /stats/summary endpoint.  [default=false]") | ||||
| 	// TODO: Remove this flag in 1.20+.  https://github.com/kubernetes/kubernetes/issues/68522 | ||||
| 	fs.MarkDeprecated("enable-cadvisor-json-endpoints", "will be removed in a future version") | ||||
| 	fs.BoolVar(&f.ReallyCrashForTesting, "really-crash-for-testing", f.ReallyCrashForTesting, "If true, when panics occur crash. Intended for testing.") | ||||
| 	fs.MarkDeprecated("really-crash-for-testing", "will be removed in a future version.") | ||||
| 	fs.Float64Var(&f.ChaosChance, "chaos-chance", f.ChaosChance, "If > 0.0, introduce random client errors and latency. Intended for testing.") | ||||
|   | ||||
| @@ -1175,22 +1175,22 @@ func RunKubelet(kubeServer *options.KubeletServer, kubeDeps *kubelet.Dependencie | ||||
| 		} | ||||
| 		klog.Info("Started kubelet as runonce") | ||||
| 	} else { | ||||
| 		startKubelet(k, podCfg, &kubeServer.KubeletConfiguration, kubeDeps, kubeServer.EnableCAdvisorJSONEndpoints, kubeServer.EnableServer) | ||||
| 		startKubelet(k, podCfg, &kubeServer.KubeletConfiguration, kubeDeps, kubeServer.EnableServer) | ||||
| 		klog.Info("Started kubelet") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, enableCAdvisorJSONEndpoints, enableServer bool) { | ||||
| func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, enableServer bool) { | ||||
| 	// start the kubelet | ||||
| 	go k.Run(podCfg.Updates()) | ||||
|  | ||||
| 	// start the kubelet server | ||||
| 	if enableServer { | ||||
| 		go k.ListenAndServe(kubeCfg, kubeDeps.TLSOptions, kubeDeps.Auth, enableCAdvisorJSONEndpoints) | ||||
| 		go k.ListenAndServe(kubeCfg, kubeDeps.TLSOptions, kubeDeps.Auth) | ||||
| 	} | ||||
| 	if kubeCfg.ReadOnlyPort > 0 { | ||||
| 		go k.ListenAndServeReadOnly(net.ParseIP(kubeCfg.Address), uint(kubeCfg.ReadOnlyPort), enableCAdvisorJSONEndpoints) | ||||
| 		go k.ListenAndServeReadOnly(net.ParseIP(kubeCfg.Address), uint(kubeCfg.ReadOnlyPort)) | ||||
| 	} | ||||
| 	if utilfeature.DefaultFeatureGate.Enabled(features.KubeletPodResources) { | ||||
| 		go k.ListenAndServePodResources() | ||||
|   | ||||
| @@ -195,9 +195,8 @@ type Bootstrap interface { | ||||
| 	GetConfiguration() kubeletconfiginternal.KubeletConfiguration | ||||
| 	BirthCry() | ||||
| 	StartGarbageCollection() | ||||
| 	ListenAndServe(kubeCfg *kubeletconfiginternal.KubeletConfiguration, tlsOptions *server.TLSOptions, auth server.AuthInterface, | ||||
| 		enableCAdvisorJSONEndpoints bool) | ||||
| 	ListenAndServeReadOnly(address net.IP, port uint, enableCAdvisorJSONEndpoints bool) | ||||
| 	ListenAndServe(kubeCfg *kubeletconfiginternal.KubeletConfiguration, tlsOptions *server.TLSOptions, auth server.AuthInterface) | ||||
| 	ListenAndServeReadOnly(address net.IP, port uint) | ||||
| 	ListenAndServePodResources() | ||||
| 	Run(<-chan kubetypes.PodUpdate) | ||||
| 	RunOnce(<-chan kubetypes.PodUpdate) ([]RunPodResult, error) | ||||
| @@ -2226,13 +2225,13 @@ func (kl *Kubelet) ResyncInterval() time.Duration { | ||||
|  | ||||
| // ListenAndServe runs the kubelet HTTP server. | ||||
| func (kl *Kubelet) ListenAndServe(kubeCfg *kubeletconfiginternal.KubeletConfiguration, tlsOptions *server.TLSOptions, | ||||
| 	auth server.AuthInterface, enableCAdvisorJSONEndpoints bool) { | ||||
| 	server.ListenAndServeKubeletServer(kl, kl.resourceAnalyzer, kubeCfg, tlsOptions, auth, enableCAdvisorJSONEndpoints) | ||||
| 	auth server.AuthInterface) { | ||||
| 	server.ListenAndServeKubeletServer(kl, kl.resourceAnalyzer, kubeCfg, tlsOptions, auth) | ||||
| } | ||||
|  | ||||
| // ListenAndServeReadOnly runs the kubelet HTTP server in read-only mode. | ||||
| func (kl *Kubelet) ListenAndServeReadOnly(address net.IP, port uint, enableCAdvisorJSONEndpoints bool) { | ||||
| 	server.ListenAndServeKubeletReadOnlyServer(kl, kl.resourceAnalyzer, address, port, enableCAdvisorJSONEndpoints) | ||||
| func (kl *Kubelet) ListenAndServeReadOnly(address net.IP, port uint) { | ||||
| 	server.ListenAndServeKubeletReadOnlyServer(kl, kl.resourceAnalyzer, address, port) | ||||
| } | ||||
|  | ||||
| // ListenAndServePodResources runs the kubelet podresources grpc service | ||||
|   | ||||
| @@ -62,7 +62,6 @@ func isSubpath(subpath, path string) bool { | ||||
| //    /stats/*   => verb=<api verb from request>, resource=nodes, name=<node name>, subresource=stats | ||||
| //    /metrics/* => verb=<api verb from request>, resource=nodes, name=<node name>, subresource=metrics | ||||
| //    /logs/*    => verb=<api verb from request>, resource=nodes, name=<node name>, subresource=log | ||||
| //    /spec/*    => verb=<api verb from request>, resource=nodes, name=<node name>, subresource=spec | ||||
| func (n nodeAuthorizerAttributesGetter) GetRequestAttributes(u user.Info, r *http.Request) authorizer.Attributes { | ||||
|  | ||||
| 	apiVerb := "" | ||||
| @@ -105,8 +104,6 @@ func (n nodeAuthorizerAttributesGetter) GetRequestAttributes(u user.Info, r *htt | ||||
| 	case isSubpath(requestPath, logsPath): | ||||
| 		// "log" to match other log subresources (pods/log, etc) | ||||
| 		attrs.Subresource = "log" | ||||
| 	case isSubpath(requestPath, specPath): | ||||
| 		attrs.Subresource = "spec" | ||||
| 	} | ||||
|  | ||||
| 	klog.V(5).InfoS("Node request attributes", "user", attrs.GetUser().GetName(), "verb", attrs.GetVerb(), "resource", attrs.GetResource(), "subresource", attrs.GetSubresource()) | ||||
|   | ||||
| @@ -131,13 +131,9 @@ func AuthzTestCases() []AuthzTestCase { | ||||
| 		"/portForward/{podNamespace}/{podID}/{uid}":         "proxy", | ||||
| 		"/run/{podNamespace}/{podID}/{containerName}":       "proxy", | ||||
| 		"/run/{podNamespace}/{podID}/{uid}/{containerName}": "proxy", | ||||
| 		"/runningpods/":    "proxy", | ||||
| 		"/spec/":           "spec", | ||||
| 		"/stats/":          "stats", | ||||
| 		"/stats/container": "stats", | ||||
| 		"/stats/summary":   "stats", | ||||
| 		"/stats/{namespace}/{podName}/{uid}/{containerName}": "stats", | ||||
| 		"/stats/{podName}/{containerName}":                   "stats", | ||||
| 		"/runningpods/":  "proxy", | ||||
| 		"/stats/":        "stats", | ||||
| 		"/stats/summary": "stats", | ||||
| 	} | ||||
| 	testCases := []AuthzTestCase{} | ||||
| 	for path, subresource := range testPaths { | ||||
|   | ||||
| @@ -84,7 +84,6 @@ const ( | ||||
| 	cadvisorMetricsPath = "/metrics/cadvisor" | ||||
| 	resourceMetricsPath = "/metrics/resource" | ||||
| 	proberMetricsPath   = "/metrics/probes" | ||||
| 	specPath            = "/spec/" | ||||
| 	statsPath           = "/stats/" | ||||
| 	logsPath            = "/logs/" | ||||
| 	pprofBasePath       = "/debug/pprof/" | ||||
| @@ -142,13 +141,12 @@ func ListenAndServeKubeletServer( | ||||
| 	resourceAnalyzer stats.ResourceAnalyzer, | ||||
| 	kubeCfg *kubeletconfiginternal.KubeletConfiguration, | ||||
| 	tlsOptions *TLSOptions, | ||||
| 	auth AuthInterface, | ||||
| 	enableCAdvisorJSONEndpoints bool) { | ||||
| 	auth AuthInterface) { | ||||
|  | ||||
| 	address := net.ParseIP(kubeCfg.Address) | ||||
| 	port := uint(kubeCfg.Port) | ||||
| 	klog.InfoS("Starting to listen", "address", address, "port", port) | ||||
| 	handler := NewServer(host, resourceAnalyzer, auth, enableCAdvisorJSONEndpoints, kubeCfg) | ||||
| 	handler := NewServer(host, resourceAnalyzer, auth, kubeCfg) | ||||
| 	s := &http.Server{ | ||||
| 		Addr:           net.JoinHostPort(address.String(), strconv.FormatUint(uint64(port), 10)), | ||||
| 		Handler:        &handler, | ||||
| @@ -168,9 +166,9 @@ func ListenAndServeKubeletServer( | ||||
| } | ||||
|  | ||||
| // ListenAndServeKubeletReadOnlyServer initializes a server to respond to HTTP network requests on the Kubelet. | ||||
| func ListenAndServeKubeletReadOnlyServer(host HostInterface, resourceAnalyzer stats.ResourceAnalyzer, address net.IP, port uint, enableCAdvisorJSONEndpoints bool) { | ||||
| func ListenAndServeKubeletReadOnlyServer(host HostInterface, resourceAnalyzer stats.ResourceAnalyzer, address net.IP, port uint) { | ||||
| 	klog.InfoS("Starting to listen read-only", "address", address, "port", port) | ||||
| 	s := NewServer(host, resourceAnalyzer, nil, enableCAdvisorJSONEndpoints, nil) | ||||
| 	s := NewServer(host, resourceAnalyzer, nil, nil) | ||||
|  | ||||
| 	server := &http.Server{ | ||||
| 		Addr:           net.JoinHostPort(address.String(), strconv.FormatUint(uint64(port), 10)), | ||||
| @@ -222,7 +220,6 @@ func NewServer( | ||||
| 	host HostInterface, | ||||
| 	resourceAnalyzer stats.ResourceAnalyzer, | ||||
| 	auth AuthInterface, | ||||
| 	enableCAdvisorJSONEndpoints bool, | ||||
| 	kubeCfg *kubeletconfiginternal.KubeletConfiguration) Server { | ||||
| 	server := Server{ | ||||
| 		host:                 host, | ||||
| @@ -235,7 +232,7 @@ func NewServer( | ||||
| 	if auth != nil { | ||||
| 		server.InstallAuthFilter() | ||||
| 	} | ||||
| 	server.InstallDefaultHandlers(enableCAdvisorJSONEndpoints) | ||||
| 	server.InstallDefaultHandlers() | ||||
| 	if kubeCfg != nil && kubeCfg.EnableDebuggingHandlers { | ||||
| 		server.InstallDebuggingHandlers() | ||||
| 		// To maintain backward compatibility serve logs and pprof only when enableDebuggingHandlers is also enabled | ||||
| @@ -312,7 +309,7 @@ func (s *Server) getMetricMethodBucket(method string) string { | ||||
|  | ||||
| // InstallDefaultHandlers registers the default set of supported HTTP request | ||||
| // patterns with the restful Container. | ||||
| func (s *Server) InstallDefaultHandlers(enableCAdvisorJSONEndpoints bool) { | ||||
| func (s *Server) InstallDefaultHandlers() { | ||||
| 	s.addMetricsBucketMatcher("healthz") | ||||
| 	healthz.InstallHandler(s.restfulCont, | ||||
| 		healthz.PingHealthz, | ||||
| @@ -331,7 +328,7 @@ func (s *Server) InstallDefaultHandlers(enableCAdvisorJSONEndpoints bool) { | ||||
| 	s.restfulCont.Add(ws) | ||||
|  | ||||
| 	s.addMetricsBucketMatcher("stats") | ||||
| 	s.restfulCont.Add(stats.CreateHandlers(statsPath, s.host, s.resourceAnalyzer, enableCAdvisorJSONEndpoints)) | ||||
| 	s.restfulCont.Add(stats.CreateHandlers(statsPath, s.host, s.resourceAnalyzer)) | ||||
|  | ||||
| 	s.addMetricsBucketMatcher("metrics") | ||||
| 	s.addMetricsBucketMatcher("metrics/cadvisor") | ||||
| @@ -387,19 +384,6 @@ func (s *Server) InstallDefaultHandlers(enableCAdvisorJSONEndpoints bool) { | ||||
| 	s.restfulCont.Handle(proberMetricsPath, | ||||
| 		compbasemetrics.HandlerFor(p, compbasemetrics.HandlerOpts{ErrorHandling: compbasemetrics.ContinueOnError}), | ||||
| 	) | ||||
|  | ||||
| 	s.addMetricsBucketMatcher("spec") | ||||
| 	if enableCAdvisorJSONEndpoints { | ||||
| 		ws := new(restful.WebService) | ||||
| 		ws. | ||||
| 			Path(specPath). | ||||
| 			Produces(restful.MIME_JSON) | ||||
| 		ws.Route(ws.GET(""). | ||||
| 			To(s.getSpec). | ||||
| 			Operation("getSpec"). | ||||
| 			Writes(cadvisorapi.MachineInfo{})) | ||||
| 		s.restfulCont.Add(ws) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // InstallDebuggingHandlers registers the HTTP request patterns that serve logs or run commands/containers | ||||
| @@ -718,16 +702,6 @@ func (s *Server) getLogs(request *restful.Request, response *restful.Response) { | ||||
| 	s.host.ServeLogs(response, request.Request) | ||||
| } | ||||
|  | ||||
| // getSpec handles spec requests against the Kubelet. | ||||
| func (s *Server) getSpec(request *restful.Request, response *restful.Response) { | ||||
| 	info, err := s.host.GetCachedMachineInfo() | ||||
| 	if err != nil { | ||||
| 		response.WriteError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
| 	response.WriteEntity(info) | ||||
| } | ||||
|  | ||||
| type execRequestParams struct { | ||||
| 	podNamespace  string | ||||
| 	podName       string | ||||
|   | ||||
| @@ -17,9 +17,7 @@ limitations under the License. | ||||
| package server | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| @@ -57,7 +55,6 @@ import ( | ||||
| 	_ "k8s.io/kubernetes/pkg/apis/core/install" | ||||
| 	kubeletconfiginternal "k8s.io/kubernetes/pkg/kubelet/apis/config" | ||||
| 	"k8s.io/kubernetes/pkg/kubelet/cm" | ||||
| 	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" | ||||
| 	"k8s.io/kubernetes/pkg/kubelet/cri/streaming" | ||||
| 	"k8s.io/kubernetes/pkg/kubelet/cri/streaming/portforward" | ||||
| 	remotecommandserver "k8s.io/kubernetes/pkg/kubelet/cri/streaming/remotecommand" | ||||
| @@ -348,7 +345,6 @@ func newServerTestWithDebuggingHandlers(kubeCfg *kubeletconfiginternal.KubeletCo | ||||
| 		fw.fakeKubelet, | ||||
| 		stats.NewResourceAnalyzer(fw.fakeKubelet, time.Minute), | ||||
| 		fw.fakeAuth, | ||||
| 		true, | ||||
| 		kubeCfg) | ||||
| 	fw.serverUnderTest = &server | ||||
| 	fw.testHTTPServer = httptest.NewServer(fw.serverUnderTest) | ||||
| @@ -363,185 +359,6 @@ func getPodName(name, namespace string) string { | ||||
| 	return name + "_" + namespace | ||||
| } | ||||
|  | ||||
| func TestContainerInfo(t *testing.T) { | ||||
| 	fw := newServerTest() | ||||
| 	defer fw.testHTTPServer.Close() | ||||
| 	expectedInfo := &cadvisorapi.ContainerInfo{} | ||||
| 	podID := "somepod" | ||||
| 	expectedPodID := getPodName(podID, "") | ||||
| 	expectedContainerName := "goodcontainer" | ||||
| 	fw.fakeKubelet.containerInfoFunc = func(podID string, uid types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) { | ||||
| 		if podID != expectedPodID || containerName != expectedContainerName { | ||||
| 			return nil, fmt.Errorf("bad podID or containerName: podID=%v; containerName=%v", podID, containerName) | ||||
| 		} | ||||
| 		return expectedInfo, nil | ||||
| 	} | ||||
|  | ||||
| 	resp, err := http.Get(fw.testHTTPServer.URL + fmt.Sprintf("/stats/%v/%v", podID, expectedContainerName)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Got error GETing: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	var receivedInfo cadvisorapi.ContainerInfo | ||||
| 	err = json.NewDecoder(resp.Body).Decode(&receivedInfo) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("received invalid json data: %v", err) | ||||
| 	} | ||||
| 	if !receivedInfo.Eq(expectedInfo) { | ||||
| 		t.Errorf("received wrong data: %#v", receivedInfo) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestContainerInfoWithUidNamespace(t *testing.T) { | ||||
| 	fw := newServerTest() | ||||
| 	defer fw.testHTTPServer.Close() | ||||
| 	expectedInfo := &cadvisorapi.ContainerInfo{} | ||||
| 	podID := "somepod" | ||||
| 	expectedNamespace := "custom" | ||||
| 	expectedPodID := getPodName(podID, expectedNamespace) | ||||
| 	expectedContainerName := "goodcontainer" | ||||
| 	fw.fakeKubelet.containerInfoFunc = func(podID string, uid types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) { | ||||
| 		if podID != expectedPodID || string(uid) != testUID || containerName != expectedContainerName { | ||||
| 			return nil, fmt.Errorf("bad podID or uid or containerName: podID=%v; uid=%v; containerName=%v", podID, uid, containerName) | ||||
| 		} | ||||
| 		return expectedInfo, nil | ||||
| 	} | ||||
|  | ||||
| 	resp, err := http.Get(fw.testHTTPServer.URL + fmt.Sprintf("/stats/%v/%v/%v/%v", expectedNamespace, podID, testUID, expectedContainerName)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Got error GETing: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	var receivedInfo cadvisorapi.ContainerInfo | ||||
| 	err = json.NewDecoder(resp.Body).Decode(&receivedInfo) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("received invalid json data: %v", err) | ||||
| 	} | ||||
| 	if !receivedInfo.Eq(expectedInfo) { | ||||
| 		t.Errorf("received wrong data: %#v", receivedInfo) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestContainerNotFound(t *testing.T) { | ||||
| 	fw := newServerTest() | ||||
| 	defer fw.testHTTPServer.Close() | ||||
| 	podID := "somepod" | ||||
| 	expectedNamespace := "custom" | ||||
| 	expectedContainerName := "slowstartcontainer" | ||||
| 	fw.fakeKubelet.containerInfoFunc = func(podID string, uid types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) { | ||||
| 		return nil, kubecontainer.ErrContainerNotFound | ||||
| 	} | ||||
| 	resp, err := http.Get(fw.testHTTPServer.URL + fmt.Sprintf("/stats/%v/%v/%v/%v", expectedNamespace, podID, testUID, expectedContainerName)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Got error GETing: %v", err) | ||||
| 	} | ||||
| 	if resp.StatusCode != http.StatusNotFound { | ||||
| 		t.Fatalf("Received status %d expecting %d", resp.StatusCode, http.StatusNotFound) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| } | ||||
|  | ||||
| func TestRootInfo(t *testing.T) { | ||||
| 	fw := newServerTest() | ||||
| 	defer fw.testHTTPServer.Close() | ||||
| 	expectedInfo := &cadvisorapi.ContainerInfo{ | ||||
| 		ContainerReference: cadvisorapi.ContainerReference{ | ||||
| 			Name: "/", | ||||
| 		}, | ||||
| 	} | ||||
| 	fw.fakeKubelet.rawInfoFunc = func(req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) { | ||||
| 		return map[string]*cadvisorapi.ContainerInfo{ | ||||
| 			expectedInfo.Name: expectedInfo, | ||||
| 		}, nil | ||||
| 	} | ||||
|  | ||||
| 	resp, err := http.Get(fw.testHTTPServer.URL + "/stats") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Got error GETing: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	var receivedInfo cadvisorapi.ContainerInfo | ||||
| 	err = json.NewDecoder(resp.Body).Decode(&receivedInfo) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("received invalid json data: %v", err) | ||||
| 	} | ||||
| 	if !receivedInfo.Eq(expectedInfo) { | ||||
| 		t.Errorf("received wrong data: %#v, expected %#v", receivedInfo, expectedInfo) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSubcontainerContainerInfo(t *testing.T) { | ||||
| 	fw := newServerTest() | ||||
| 	defer fw.testHTTPServer.Close() | ||||
| 	const kubeletContainer = "/kubelet" | ||||
| 	const kubeletSubContainer = "/kubelet/sub" | ||||
| 	expectedInfo := map[string]*cadvisorapi.ContainerInfo{ | ||||
| 		kubeletContainer: { | ||||
| 			ContainerReference: cadvisorapi.ContainerReference{ | ||||
| 				Name: kubeletContainer, | ||||
| 			}, | ||||
| 		}, | ||||
| 		kubeletSubContainer: { | ||||
| 			ContainerReference: cadvisorapi.ContainerReference{ | ||||
| 				Name: kubeletSubContainer, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	fw.fakeKubelet.rawInfoFunc = func(req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) { | ||||
| 		return expectedInfo, nil | ||||
| 	} | ||||
|  | ||||
| 	request := fmt.Sprintf("{\"containerName\":%q, \"subcontainers\": true}", kubeletContainer) | ||||
| 	resp, err := http.Post(fw.testHTTPServer.URL+"/stats/container", "application/json", bytes.NewBuffer([]byte(request))) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Got error GETing: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	var receivedInfo map[string]*cadvisorapi.ContainerInfo | ||||
| 	err = json.NewDecoder(resp.Body).Decode(&receivedInfo) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Received invalid json data: %v", err) | ||||
| 	} | ||||
| 	if len(receivedInfo) != len(expectedInfo) { | ||||
| 		t.Errorf("Received wrong data: %#v, expected %#v", receivedInfo, expectedInfo) | ||||
| 	} | ||||
|  | ||||
| 	for _, containerName := range []string{kubeletContainer, kubeletSubContainer} { | ||||
| 		if _, ok := receivedInfo[containerName]; !ok { | ||||
| 			t.Errorf("Expected container %q to be present in result: %#v", containerName, receivedInfo) | ||||
| 		} | ||||
| 		if !receivedInfo[containerName].Eq(expectedInfo[containerName]) { | ||||
| 			t.Errorf("Invalid result for %q: Expected %#v, received %#v", containerName, expectedInfo[containerName], receivedInfo[containerName]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMachineInfo(t *testing.T) { | ||||
| 	fw := newServerTest() | ||||
| 	defer fw.testHTTPServer.Close() | ||||
| 	expectedInfo := &cadvisorapi.MachineInfo{ | ||||
| 		NumCores:       4, | ||||
| 		MemoryCapacity: 1024, | ||||
| 	} | ||||
| 	fw.fakeKubelet.machineInfoFunc = func() (*cadvisorapi.MachineInfo, error) { | ||||
| 		return expectedInfo, nil | ||||
| 	} | ||||
|  | ||||
| 	resp, err := http.Get(fw.testHTTPServer.URL + "/spec") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Got error GETing: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	var receivedInfo cadvisorapi.MachineInfo | ||||
| 	err = json.NewDecoder(resp.Body).Decode(&receivedInfo) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("received invalid json data: %v", err) | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(&receivedInfo, expectedInfo) { | ||||
| 		t.Errorf("received wrong data: %#v", receivedInfo) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestServeLogs(t *testing.T) { | ||||
| 	fw := newServerTest() | ||||
| 	defer fw.testHTTPServer.Close() | ||||
| @@ -1470,12 +1287,8 @@ func TestMetricBuckets(t *testing.T) { | ||||
| 		"run":                             {url: "/run/podNamespace/podID/containerName", bucket: "run"}, | ||||
| 		"run with uid":                    {url: "/run/podNamespace/podID/uid/containerName", bucket: "run"}, | ||||
| 		"runningpods":                     {url: "/runningpods/", bucket: "runningpods"}, | ||||
| 		"spec":                            {url: "/spec/", bucket: "spec"}, | ||||
| 		"stats":                           {url: "/stats/", bucket: "stats"}, | ||||
| 		"stats container sub":             {url: "/stats/container", bucket: "stats"}, | ||||
| 		"stats summary sub":               {url: "/stats/summary", bucket: "stats"}, | ||||
| 		"stats containerName with uid":    {url: "/stats/namespace/podName/uid/containerName", bucket: "stats"}, | ||||
| 		"stats containerName":             {url: "/stats/podName/containerName", bucket: "stats"}, | ||||
| 		"invalid path":                    {url: "/junk", bucket: "other"}, | ||||
| 		"invalid path starting with good": {url: "/healthzjunk", bucket: "other"}, | ||||
| 	} | ||||
| @@ -1530,34 +1343,6 @@ func TestDebuggingDisabledHandlers(t *testing.T) { | ||||
| 	for _, p := range paths { | ||||
| 		verifyEndpointResponse(t, fw, p, "Debug endpoints are disabled.\n") | ||||
| 	} | ||||
|  | ||||
| 	// test some other paths, make sure they're working | ||||
| 	containerInfo := &cadvisorapi.ContainerInfo{ | ||||
| 		ContainerReference: cadvisorapi.ContainerReference{ | ||||
| 			Name: "/", | ||||
| 		}, | ||||
| 	} | ||||
| 	fw.fakeKubelet.rawInfoFunc = func(req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) { | ||||
| 		return map[string]*cadvisorapi.ContainerInfo{ | ||||
| 			containerInfo.Name: containerInfo, | ||||
| 		}, nil | ||||
| 	} | ||||
|  | ||||
| 	resp, err := http.Get(fw.testHTTPServer.URL + "/stats") | ||||
| 	require.NoError(t, err) | ||||
| 	assert.Equal(t, http.StatusOK, resp.StatusCode) | ||||
|  | ||||
| 	machineInfo := &cadvisorapi.MachineInfo{ | ||||
| 		NumCores:       4, | ||||
| 		MemoryCapacity: 1024, | ||||
| 	} | ||||
| 	fw.fakeKubelet.machineInfoFunc = func() (*cadvisorapi.MachineInfo, error) { | ||||
| 		return machineInfo, nil | ||||
| 	} | ||||
|  | ||||
| 	resp, err = http.Get(fw.testHTTPServer.URL + "/spec") | ||||
| 	require.NoError(t, err) | ||||
| 	assert.Equal(t, http.StatusOK, resp.StatusCode) | ||||
| } | ||||
|  | ||||
| func TestDisablingLogAndProfilingHandler(t *testing.T) { | ||||
|   | ||||
| @@ -17,12 +17,8 @@ limitations under the License. | ||||
| package stats | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"path" | ||||
| 	"time" | ||||
|  | ||||
| 	restful "github.com/emicklei/go-restful" | ||||
| 	cadvisorapi "github.com/google/cadvisor/info/v1" | ||||
| @@ -31,7 +27,6 @@ import ( | ||||
| 	"k8s.io/klog/v2" | ||||
|  | ||||
| 	"k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| 	statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" | ||||
| 	"k8s.io/kubernetes/pkg/kubelet/cm" | ||||
| @@ -113,31 +108,20 @@ type handler struct { | ||||
| } | ||||
|  | ||||
| // CreateHandlers creates the REST handlers for the stats. | ||||
| func CreateHandlers(rootPath string, provider Provider, summaryProvider SummaryProvider, enableCAdvisorJSONEndpoints bool) *restful.WebService { | ||||
| func CreateHandlers(rootPath string, provider Provider, summaryProvider SummaryProvider) *restful.WebService { | ||||
| 	h := &handler{provider, summaryProvider} | ||||
|  | ||||
| 	ws := &restful.WebService{} | ||||
| 	ws.Path(rootPath). | ||||
| 		Produces(restful.MIME_JSON) | ||||
|  | ||||
| 	type endpoint struct { | ||||
| 	endpoints := []struct { | ||||
| 		path    string | ||||
| 		handler restful.RouteFunction | ||||
| 	} | ||||
|  | ||||
| 	endpoints := []endpoint{ | ||||
| 	}{ | ||||
| 		{"/summary", h.handleSummary}, | ||||
| 	} | ||||
|  | ||||
| 	if enableCAdvisorJSONEndpoints { | ||||
| 		endpoints = append(endpoints, | ||||
| 			endpoint{"", h.handleStats}, | ||||
| 			endpoint{"/container", h.handleSystemContainer}, | ||||
| 			endpoint{"/{podName}/{containerName}", h.handlePodContainer}, | ||||
| 			endpoint{"/{namespace}/{podName}/{uid}/{containerName}", h.handlePodContainer}, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	for _, e := range endpoints { | ||||
| 		for _, method := range []string{"GET", "POST"} { | ||||
| 			ws.Route(ws. | ||||
| @@ -150,72 +134,6 @@ func CreateHandlers(rootPath string, provider Provider, summaryProvider SummaryP | ||||
| 	return ws | ||||
| } | ||||
|  | ||||
| type statsRequest struct { | ||||
| 	// The name of the container for which to request stats. | ||||
| 	// Default: / | ||||
| 	// +optional | ||||
| 	ContainerName string `json:"containerName,omitempty"` | ||||
|  | ||||
| 	// Max number of stats to return. | ||||
| 	// If start and end time are specified this limit is ignored. | ||||
| 	// Default: 60 | ||||
| 	// +optional | ||||
| 	NumStats int `json:"num_stats,omitempty"` | ||||
|  | ||||
| 	// Start time for which to query information. | ||||
| 	// If omitted, the beginning of time is assumed. | ||||
| 	// +optional | ||||
| 	Start time.Time `json:"start,omitempty"` | ||||
|  | ||||
| 	// End time for which to query information. | ||||
| 	// If omitted, current time is assumed. | ||||
| 	// +optional | ||||
| 	End time.Time `json:"end,omitempty"` | ||||
|  | ||||
| 	// Whether to also include information from subcontainers. | ||||
| 	// Default: false. | ||||
| 	// +optional | ||||
| 	Subcontainers bool `json:"subcontainers,omitempty"` | ||||
| } | ||||
|  | ||||
| func (r *statsRequest) cadvisorRequest() *cadvisorapi.ContainerInfoRequest { | ||||
| 	return &cadvisorapi.ContainerInfoRequest{ | ||||
| 		NumStats: r.NumStats, | ||||
| 		Start:    r.Start, | ||||
| 		End:      r.End, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func parseStatsRequest(request *restful.Request) (statsRequest, error) { | ||||
| 	// Default request. | ||||
| 	query := statsRequest{ | ||||
| 		NumStats: 60, | ||||
| 	} | ||||
|  | ||||
| 	err := json.NewDecoder(request.Request.Body).Decode(&query) | ||||
| 	if err != nil && err != io.EOF { | ||||
| 		return query, err | ||||
| 	} | ||||
| 	return query, nil | ||||
| } | ||||
|  | ||||
| // Handles root container stats requests to /stats | ||||
| func (h *handler) handleStats(request *restful.Request, response *restful.Response) { | ||||
| 	query, err := parseStatsRequest(request) | ||||
| 	if err != nil { | ||||
| 		handleError(response, "/stats", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Root container stats. | ||||
| 	statsMap, err := h.provider.GetRawContainerInfo("/", query.cadvisorRequest(), false) | ||||
| 	if err != nil { | ||||
| 		handleError(response, fmt.Sprintf("/stats %v", query), err) | ||||
| 		return | ||||
| 	} | ||||
| 	writeResponse(response, statsMap["/"]) | ||||
| } | ||||
|  | ||||
| // Handles stats summary requests to /stats/summary | ||||
| // If "only_cpu_and_memory" GET param is true then only cpu and memory is returned in response. | ||||
| func (h *handler) handleSummary(request *restful.Request, response *restful.Response) { | ||||
| @@ -244,74 +162,6 @@ func (h *handler) handleSummary(request *restful.Request, response *restful.Resp | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Handles non-kubernetes container stats requests to /stats/container/ | ||||
| func (h *handler) handleSystemContainer(request *restful.Request, response *restful.Response) { | ||||
| 	query, err := parseStatsRequest(request) | ||||
| 	if err != nil { | ||||
| 		handleError(response, "/stats/container", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Non-Kubernetes container stats. | ||||
| 	containerName := path.Join("/", query.ContainerName) | ||||
| 	stats, err := h.provider.GetRawContainerInfo( | ||||
| 		containerName, query.cadvisorRequest(), query.Subcontainers) | ||||
| 	if err != nil { | ||||
| 		if _, ok := stats[containerName]; ok { | ||||
| 			// If the failure is partial, log it and return a best-effort response. | ||||
| 			klog.ErrorS(err, "Partial failure issuing GetRawContainerInfo", "query", query) | ||||
| 		} else { | ||||
| 			handleError(response, fmt.Sprintf("/stats/container %v", query), err) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	writeResponse(response, stats) | ||||
| } | ||||
|  | ||||
| // Handles kubernetes pod/container stats requests to: | ||||
| // /stats/<pod name>/<container name> | ||||
| // /stats/<namespace>/<pod name>/<uid>/<container name> | ||||
| func (h *handler) handlePodContainer(request *restful.Request, response *restful.Response) { | ||||
| 	query, err := parseStatsRequest(request) | ||||
| 	if err != nil { | ||||
| 		handleError(response, request.Request.URL.String(), err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Default parameters. | ||||
| 	params := map[string]string{ | ||||
| 		"namespace": metav1.NamespaceDefault, | ||||
| 		"uid":       "", | ||||
| 	} | ||||
| 	for k, v := range request.PathParameters() { | ||||
| 		params[k] = v | ||||
| 	} | ||||
|  | ||||
| 	if params["podName"] == "" || params["containerName"] == "" { | ||||
| 		response.WriteErrorString(http.StatusBadRequest, | ||||
| 			fmt.Sprintf("Invalid pod container request: %v", params)) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	pod, ok := h.provider.GetPodByName(params["namespace"], params["podName"]) | ||||
| 	if !ok { | ||||
| 		klog.V(4).InfoS("Container not found", "pod", klog.KRef(params["namespace"], params["podName"])) | ||||
| 		response.WriteError(http.StatusNotFound, kubecontainer.ErrContainerNotFound) | ||||
| 		return | ||||
| 	} | ||||
| 	stats, err := h.provider.GetContainerInfo( | ||||
| 		kubecontainer.GetPodFullName(pod), | ||||
| 		types.UID(params["uid"]), | ||||
| 		params["containerName"], | ||||
| 		query.cadvisorRequest()) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		handleError(response, fmt.Sprintf("%s %v", request.Request.URL.String(), query), err) | ||||
| 		return | ||||
| 	} | ||||
| 	writeResponse(response, stats) | ||||
| } | ||||
|  | ||||
| func writeResponse(response *restful.Response, stats interface{}) { | ||||
| 	if err := response.WriteAsJson(stats); err != nil { | ||||
| 		klog.ErrorS(err, "Error writing response") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 pacoxu
					pacoxu