diff --git a/cmd/kubelet/app/options/options.go b/cmd/kubelet/app/options/options.go index e72ce8bb0fe..9774f5ee823 100644 --- a/cmd/kubelet/app/options/options.go +++ b/cmd/kubelet/app/options/options.go @@ -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.") diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index 6a60dc3206d..499e47f7b08 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -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() diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 76ec6217520..6f640c359a3 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -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 diff --git a/pkg/kubelet/server/auth.go b/pkg/kubelet/server/auth.go index 64228747979..469039b9d2b 100644 --- a/pkg/kubelet/server/auth.go +++ b/pkg/kubelet/server/auth.go @@ -62,7 +62,6 @@ func isSubpath(subpath, path string) bool { // /stats/* => verb=, resource=nodes, name=, subresource=stats // /metrics/* => verb=, resource=nodes, name=, subresource=metrics // /logs/* => verb=, resource=nodes, name=, subresource=log -// /spec/* => verb=, resource=nodes, 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()) diff --git a/pkg/kubelet/server/auth_test.go b/pkg/kubelet/server/auth_test.go index ad2c2c61540..dc827ffd105 100644 --- a/pkg/kubelet/server/auth_test.go +++ b/pkg/kubelet/server/auth_test.go @@ -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 { diff --git a/pkg/kubelet/server/server.go b/pkg/kubelet/server/server.go index 8f183f02108..7d9f00111da 100644 --- a/pkg/kubelet/server/server.go +++ b/pkg/kubelet/server/server.go @@ -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 diff --git a/pkg/kubelet/server/server_test.go b/pkg/kubelet/server/server_test.go index 745ff5843c6..12c32f71d5e 100644 --- a/pkg/kubelet/server/server_test.go +++ b/pkg/kubelet/server/server_test.go @@ -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) { diff --git a/pkg/kubelet/server/stats/handler.go b/pkg/kubelet/server/stats/handler.go index c4985d248df..c3781cf9b21 100644 --- a/pkg/kubelet/server/stats/handler.go +++ b/pkg/kubelet/server/stats/handler.go @@ -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// -// /stats//// -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")