123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- /*
- Copyright 2015 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package metrics
- import (
- "bufio"
- "fmt"
- "net/http"
- "net/http/httptest"
- "runtime"
- "testing"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime/schema"
- clientset "k8s.io/client-go/kubernetes"
- restclient "k8s.io/client-go/rest"
- "k8s.io/kubernetes/test/integration/framework"
- "github.com/golang/protobuf/proto"
- prometheuspb "github.com/prometheus/client_model/go"
- "k8s.io/klog"
- )
- const scrapeRequestHeader = "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=compact-text"
- func scrapeMetrics(s *httptest.Server) ([]*prometheuspb.MetricFamily, error) {
- req, err := http.NewRequest("GET", s.URL+"/metrics", nil)
- if err != nil {
- return nil, fmt.Errorf("Unable to create http request: %v", err)
- }
- // Ask the prometheus exporter for its text protocol buffer format, since it's
- // much easier to parse than its plain-text format. Don't use the serialized
- // proto representation since it uses a non-standard varint delimiter between
- // metric families.
- req.Header.Add("Accept", scrapeRequestHeader)
- client := &http.Client{}
- resp, err := client.Do(req)
- if err != nil {
- return nil, fmt.Errorf("Unable to contact metrics endpoint of master: %v", err)
- }
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- return nil, fmt.Errorf("Non-200 response trying to scrape metrics from master: %v", resp)
- }
- // Each line in the response body should contain all the data for a single metric.
- var metrics []*prometheuspb.MetricFamily
- scanner := bufio.NewScanner(resp.Body)
- // Increase buffer size, since default one is too small for reading
- // the /metrics contents.
- scanner.Buffer(make([]byte, 10), 131072)
- for scanner.Scan() {
- var metric prometheuspb.MetricFamily
- if err := proto.UnmarshalText(scanner.Text(), &metric); err != nil {
- return nil, fmt.Errorf("Failed to unmarshal line of metrics response: %v", err)
- }
- klog.V(4).Infof("Got metric %q", metric.GetName())
- metrics = append(metrics, &metric)
- }
- return metrics, nil
- }
- func checkForExpectedMetrics(t *testing.T, metrics []*prometheuspb.MetricFamily, expectedMetrics []string) {
- foundMetrics := make(map[string]bool)
- for _, metric := range metrics {
- foundMetrics[metric.GetName()] = true
- }
- for _, expected := range expectedMetrics {
- if _, found := foundMetrics[expected]; !found {
- t.Errorf("Master metrics did not include expected metric %q", expected)
- }
- }
- }
- func TestMasterProcessMetrics(t *testing.T) {
- if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
- t.Skipf("not supported on GOOS=%s", runtime.GOOS)
- }
- _, s, closeFn := framework.RunAMaster(nil)
- defer closeFn()
- metrics, err := scrapeMetrics(s)
- if err != nil {
- t.Fatal(err)
- }
- checkForExpectedMetrics(t, metrics, []string{
- "process_start_time_seconds",
- "process_cpu_seconds_total",
- "process_open_fds",
- "process_resident_memory_bytes",
- })
- }
- func TestApiserverMetrics(t *testing.T) {
- _, s, closeFn := framework.RunAMaster(nil)
- defer closeFn()
- // Make a request to the apiserver to ensure there's at least one data point
- // for the metrics we're expecting -- otherwise, they won't be exported.
- client := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}})
- if _, err := client.CoreV1().Pods(metav1.NamespaceDefault).List(metav1.ListOptions{}); err != nil {
- t.Fatalf("unexpected error getting pods: %v", err)
- }
- metrics, err := scrapeMetrics(s)
- if err != nil {
- t.Fatal(err)
- }
- checkForExpectedMetrics(t, metrics, []string{
- "apiserver_request_total",
- "apiserver_request_duration_seconds",
- "etcd_request_duration_seconds",
- })
- }
|