github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/integration/heapster_api_test.go (about)

     1  // Copyright 2015 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package integration
    16  
    17  import (
    18  	"encoding/json"
    19  	"flag"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/golang/glog"
    28  	"github.com/stretchr/testify/require"
    29  	kube_v1 "k8s.io/api/core/v1"
    30  	apiErrors "k8s.io/apimachinery/pkg/api/errors"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	"k8s.io/apimachinery/pkg/labels"
    33  	"k8s.io/apimachinery/pkg/util/sets"
    34  	api_v1 "k8s.io/heapster/metrics/api/v1/types"
    35  	"k8s.io/heapster/metrics/core"
    36  	metrics_api "k8s.io/metrics/pkg/apis/metrics/v1alpha1"
    37  )
    38  
    39  const (
    40  	targetTags       = "kubernetes-minion"
    41  	heapsterBuildDir = "../"
    42  )
    43  
    44  var (
    45  	testZone                   = flag.String("test_zone", "us-central1-b", "GCE zone where the test will be executed")
    46  	kubeVersions               = flag.String("kube_versions", "", "Comma separated list of kube versions to test against. By default will run the test against an existing cluster")
    47  	heapsterControllerFile     = flag.String("heapster_controller", "../deploy/kube-config/standalone-test/heapster-controller.yaml", "Path to heapster replication controller file.")
    48  	heapsterServiceFile        = flag.String("heapster_service", "../deploy/kube-config/standalone-test/heapster-service.yaml", "Path to heapster service file.")
    49  	heapsterRBACFile           = flag.String("heapster_rbac", "../deploy/kube-config/standalone-test/heapster-rbac.yaml", "Path to heapster rbac file.")
    50  	heapsterServiceAccountFile = flag.String("heapster_service_account", "../deploy/kube-config/standalone-test/heapster-service-account.yaml", "Path to heapster service account file.")
    51  	heapsterImage              = flag.String("heapster_image", "heapster:e2e_test", "heapster docker image that needs to be tested.")
    52  	avoidBuild                 = flag.Bool("nobuild", false, "When true, a new heapster docker image will not be created and pushed to test cluster nodes.")
    53  	namespace                  = flag.String("namespace", "heapster-e2e-tests", "namespace to be used for testing, it will be deleted at the beginning of the test if exists")
    54  	maxRetries                 = flag.Int("retries", 20, "Number of attempts before failing this test.")
    55  	runForever                 = flag.Bool("run_forever", false, "If true, the tests are run in a loop forever.")
    56  	testUser                   = flag.String("test_user", "", "GCE user when copy file to host")
    57  )
    58  
    59  func deleteAll(fm kubeFramework, ns string, service *kube_v1.Service, rc *kube_v1.ReplicationController) error {
    60  	glog.V(2).Infof("Deleting ns %s...", ns)
    61  	err := fm.DeleteNs(ns)
    62  	if err != nil {
    63  		glog.V(2).Infof("Failed to delete %s", ns)
    64  		return err
    65  	}
    66  	glog.V(2).Infof("Deleted ns %s.", ns)
    67  	return nil
    68  }
    69  
    70  func createAll(fm kubeFramework, ns string, service **kube_v1.Service, rc **kube_v1.ReplicationController) error {
    71  	glog.V(2).Infof("Creating ns %s...", ns)
    72  	namespace := kube_v1.Namespace{
    73  		TypeMeta: metav1.TypeMeta{
    74  			Kind:       "Namespace",
    75  			APIVersion: "v1",
    76  		},
    77  		ObjectMeta: metav1.ObjectMeta{
    78  			Name: ns,
    79  		},
    80  	}
    81  	if _, err := fm.CreateNs(&namespace); err != nil {
    82  		glog.V(2).Infof("Failed to create ns: %v", err)
    83  		return err
    84  	}
    85  
    86  	glog.V(2).Infof("Created ns %s.", ns)
    87  
    88  	glog.V(2).Infof("Creating rc %s/%s...", ns, (*rc).Name)
    89  	if newRc, err := fm.CreateRC(ns, *rc); err != nil {
    90  		glog.V(2).Infof("Failed to create rc: %v", err)
    91  		return err
    92  	} else {
    93  		*rc = newRc
    94  	}
    95  	glog.V(2).Infof("Created rc %s/%s.", ns, (*rc).Name)
    96  
    97  	glog.V(2).Infof("Creating service %s/%s...", ns, (*service).Name)
    98  	if newSvc, err := fm.CreateService(ns, *service); err != nil {
    99  		glog.V(2).Infof("Failed to create service: %v", err)
   100  		return err
   101  	} else {
   102  		*service = newSvc
   103  	}
   104  	glog.V(2).Infof("Created service %s/%s.", ns, (*service).Name)
   105  
   106  	return nil
   107  }
   108  
   109  func removeHeapsterImage(fm kubeFramework, zone string) error {
   110  	glog.V(2).Infof("Removing heapster image.")
   111  	if err := removeDockerImage(*heapsterImage); err != nil {
   112  		glog.Errorf("Failed to remove Heapster image: %v", err)
   113  	} else {
   114  		glog.V(2).Infof("Heapster image removed.")
   115  	}
   116  	if nodes, err := fm.GetNodeNames(); err == nil {
   117  		for _, node := range nodes {
   118  			host := strings.Split(node, ".")[0]
   119  			cleanupRemoteHost(host, zone)
   120  		}
   121  	} else {
   122  		glog.Errorf("failed to cleanup nodes - %v", err)
   123  	}
   124  	return nil
   125  }
   126  
   127  func buildAndPushHeapsterImage(hostnames []string, zone string) error {
   128  	glog.V(2).Info("Building and pushing Heapster image...")
   129  	curwd, err := os.Getwd()
   130  	if err != nil {
   131  		return err
   132  	}
   133  	if err := os.Chdir(heapsterBuildDir); err != nil {
   134  		return err
   135  	}
   136  	if err := buildDockerImage(*heapsterImage); err != nil {
   137  		return err
   138  	}
   139  	for _, host := range hostnames {
   140  		if err := copyDockerImage(*heapsterImage, host, zone); err != nil {
   141  			return err
   142  		}
   143  	}
   144  	glog.V(2).Info("Heapster image pushed.")
   145  	return os.Chdir(curwd)
   146  }
   147  
   148  func getHeapsterRcAndSvc(fm kubeFramework) (*kube_v1.Service, *kube_v1.ReplicationController, error) {
   149  	// Add test docker image
   150  	rc, err := fm.ParseRC(*heapsterControllerFile)
   151  	if err != nil {
   152  		return nil, nil, fmt.Errorf("failed to parse heapster controller - %v", err)
   153  	}
   154  	for i := range rc.Spec.Template.Spec.Containers {
   155  		rc.Spec.Template.Spec.Containers[i].Image = *heapsterImage
   156  		rc.Spec.Template.Spec.Containers[i].ImagePullPolicy = kube_v1.PullNever
   157  		// increase logging level
   158  		rc.Spec.Template.Spec.Containers[i].Env = append(rc.Spec.Template.Spec.Containers[0].Env, kube_v1.EnvVar{Name: "FLAGS", Value: "--vmodule=*=3"})
   159  	}
   160  
   161  	svc, err := fm.ParseService(*heapsterServiceFile)
   162  	if err != nil {
   163  		return nil, nil, fmt.Errorf("failed to parse heapster service - %v", err)
   164  	}
   165  
   166  	return svc, rc, nil
   167  }
   168  
   169  func setupHeapsterServiceAccount(fm kubeFramework) error {
   170  	sa, err := fm.ParseServiceAccount(*heapsterServiceAccountFile)
   171  	if err != nil {
   172  		return fmt.Errorf("failed to parse heapster serviceaccount - %v", err)
   173  	}
   174  
   175  	glog.V(2).Infof("Creating serviceaccount %s/%s...", (*sa).Namespace, (*sa).Name)
   176  	if err := fm.CreateServiceAccount(sa); err != nil {
   177  		glog.V(2).Infof("Failed to create serviceaccount: %v", err)
   178  		return err
   179  	}
   180  
   181  	return nil
   182  }
   183  
   184  func setupHeapsterRBAC(fm kubeFramework) error {
   185  	rbac, err := fm.ParseRBAC(*heapsterRBACFile)
   186  	if err != nil {
   187  		return fmt.Errorf("failed to parse heapster rbac - %v", err)
   188  	}
   189  
   190  	glog.V(2).Infof("Creating rbac %s...", (*rbac).Name)
   191  	if err := fm.CreateRBAC(rbac); err != nil {
   192  		glog.V(2).Infof("Failed to create rbac: %v", err)
   193  		return err
   194  	}
   195  
   196  	return nil
   197  }
   198  
   199  func buildAndPushDockerImages(fm kubeFramework, zone string) error {
   200  	if *avoidBuild {
   201  		return nil
   202  	}
   203  	nodes, err := fm.GetNodeNames()
   204  	if err != nil {
   205  		return err
   206  	}
   207  	hostnames := []string{}
   208  	for _, node := range nodes {
   209  		nodeHost := strings.Split(node, ".")[0]
   210  		if *testUser != "" {
   211  			nodeHost = fmt.Sprintf("%s@%s", *testUser, nodeHost)
   212  		}
   213  		hostnames = append(hostnames, nodeHost)
   214  	}
   215  
   216  	return buildAndPushHeapsterImage(hostnames, zone)
   217  }
   218  
   219  const (
   220  	metricsEndpoint       = "/api/v1/metric-export"
   221  	metricsSchemaEndpoint = "/api/v1/metric-export-schema"
   222  )
   223  
   224  func getTimeseries(fm kubeFramework, svc *kube_v1.Service) ([]*api_v1.Timeseries, error) {
   225  	body, err := fm.Client().CoreV1().RESTClient().Get().
   226  		Namespace(svc.Namespace).
   227  		Prefix("proxy").
   228  		Resource("services").
   229  		Name(svc.Name).
   230  		Suffix(metricsEndpoint).
   231  		Do().Raw()
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	var timeseries []*api_v1.Timeseries
   236  	if err := json.Unmarshal(body, &timeseries); err != nil {
   237  		glog.V(2).Infof("Timeseries error: %v %v", err, string(body))
   238  		return nil, err
   239  	}
   240  	return timeseries, nil
   241  }
   242  
   243  func getSchema(fm kubeFramework, svc *kube_v1.Service) (*api_v1.TimeseriesSchema, error) {
   244  	body, err := fm.Client().CoreV1().RESTClient().Get().
   245  		Namespace(svc.Namespace).
   246  		Prefix("proxy").
   247  		Resource("services").
   248  		Name(svc.Name).
   249  		Suffix(metricsSchemaEndpoint).
   250  		Do().Raw()
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  	var timeseriesSchema api_v1.TimeseriesSchema
   255  	if err := json.Unmarshal(body, &timeseriesSchema); err != nil {
   256  		glog.V(2).Infof("Metrics schema error: %v  %v", err, string(body))
   257  		return nil, err
   258  	}
   259  	return &timeseriesSchema, nil
   260  }
   261  
   262  var expectedSystemContainers = map[string]struct{}{
   263  	"machine":    {},
   264  	"kubelet":    {},
   265  	"kube-proxy": {},
   266  	// TODO(piosz): Uncomment once https://github.com/kubernetes/kubernetes/issues/37453 is fixed
   267  	// "system":        {},
   268  	"docker-daemon": {},
   269  }
   270  
   271  func isContainerBaseImageExpected(ts *api_v1.Timeseries) bool {
   272  	cName := ts.Labels[core.LabelContainerName.Key]
   273  	// TODO(piosz): remove this if once https://github.com/kubernetes/kubernetes/issues/37453 is fixed
   274  	if cName == "system" {
   275  		return false
   276  	}
   277  	_, exists := expectedSystemContainers[cName]
   278  	return !exists
   279  }
   280  
   281  func runMetricExportTest(fm kubeFramework, svc *kube_v1.Service) error {
   282  	podList, err := fm.GetPodsRunningOnNodes()
   283  	if err != nil {
   284  		return err
   285  	}
   286  	expectedPods := make([]string, 0, len(podList))
   287  	for _, pod := range podList {
   288  		expectedPods = append(expectedPods, pod.Name)
   289  	}
   290  	glog.V(0).Infof("Expected pods: %v", expectedPods)
   291  
   292  	expectedNodes, err := fm.GetNodeNames()
   293  	if err != nil {
   294  		return err
   295  	}
   296  	glog.V(0).Infof("Expected nodes: %v", expectedNodes)
   297  
   298  	timeseries, err := getTimeseries(fm, svc)
   299  	if err != nil {
   300  		return err
   301  	}
   302  	if len(timeseries) == 0 {
   303  		return fmt.Errorf("expected non zero timeseries")
   304  	}
   305  	schema, err := getSchema(fm, svc)
   306  	if err != nil {
   307  		return err
   308  	}
   309  	// Build a map of metric names to metric descriptors.
   310  	mdMap := map[string]*api_v1.MetricDescriptor{}
   311  	for idx := range schema.Metrics {
   312  		mdMap[schema.Metrics[idx].Name] = &schema.Metrics[idx]
   313  	}
   314  	actualPods := map[string]bool{}
   315  	actualNodes := map[string]bool{}
   316  	actualSystemContainers := map[string]map[string]struct{}{}
   317  	for _, ts := range timeseries {
   318  		// Verify the relevant labels are present.
   319  		// All common labels must be present.
   320  		podName, podMetric := ts.Labels[core.LabelPodName.Key]
   321  
   322  		for _, label := range core.CommonLabels() {
   323  			_, exists := ts.Labels[label.Key]
   324  			if !exists {
   325  				return fmt.Errorf("timeseries: %v does not contain common label: %v", ts, label)
   326  			}
   327  		}
   328  		if podMetric {
   329  			for _, label := range core.PodLabels() {
   330  				_, exists := ts.Labels[label.Key]
   331  				if !exists {
   332  					return fmt.Errorf("timeseries: %v does not contain pod label: %v", ts, label)
   333  				}
   334  			}
   335  		}
   336  
   337  		if podMetric {
   338  			actualPods[podName] = true
   339  			// Extra explicit check that the expecte metrics are there:
   340  			requiredLabels := []string{
   341  				core.LabelPodNamespaceUID.Key,
   342  				core.LabelPodId.Key,
   343  				core.LabelHostID.Key,
   344  				// container name is checked later
   345  			}
   346  			for _, label := range requiredLabels {
   347  				_, exists := ts.Labels[label]
   348  				if !exists {
   349  					return fmt.Errorf("timeseries: %v does not contain required label: %v", ts, label)
   350  				}
   351  			}
   352  
   353  		} else {
   354  			if cName, ok := ts.Labels[core.LabelContainerName.Key]; ok {
   355  				hostname, ok := ts.Labels[core.LabelHostname.Key]
   356  				if !ok {
   357  					return fmt.Errorf("hostname label missing on container %+v", ts)
   358  				}
   359  
   360  				if cName == "machine" {
   361  					actualNodes[hostname] = true
   362  				} else {
   363  					for _, label := range core.ContainerLabels() {
   364  						if label == core.LabelContainerBaseImage && !isContainerBaseImageExpected(ts) {
   365  							continue
   366  						}
   367  						_, exists := ts.Labels[label.Key]
   368  						if !exists {
   369  							return fmt.Errorf("timeseries: %v does not contain container label: %v", ts, label)
   370  						}
   371  					}
   372  				}
   373  
   374  				if _, exists := expectedSystemContainers[cName]; exists {
   375  					if actualSystemContainers[cName] == nil {
   376  						actualSystemContainers[cName] = map[string]struct{}{}
   377  					}
   378  					actualSystemContainers[cName][hostname] = struct{}{}
   379  				}
   380  			} else {
   381  				return fmt.Errorf("container_name label missing on timeseries - %v", ts)
   382  			}
   383  		}
   384  
   385  		// Explicitly check for resource id
   386  		explicitRequirement := map[string][]string{
   387  			core.MetricFilesystemUsage.MetricDescriptor.Name: {core.LabelResourceID.Key},
   388  			core.MetricFilesystemLimit.MetricDescriptor.Name: {core.LabelResourceID.Key},
   389  			core.MetricFilesystemAvailable.Name:              {core.LabelResourceID.Key},
   390  			core.MetricFilesystemInodes.Name:                 {core.LabelResourceID.Key},
   391  			core.MetricFilesystemInodesFree.Name:             {core.LabelResourceID.Key},
   392  			core.MetricAcceleratorMemoryTotal.Name:           {core.LabelAcceleratorMake.Key, core.LabelAcceleratorModel.Key, core.LabelAcceleratorID.Key},
   393  			core.MetricAcceleratorMemoryUsed.Name:            {core.LabelAcceleratorMake.Key, core.LabelAcceleratorModel.Key, core.LabelAcceleratorID.Key},
   394  			core.MetricAcceleratorDutyCycle.Name:             {core.LabelAcceleratorMake.Key, core.LabelAcceleratorModel.Key, core.LabelAcceleratorID.Key},
   395  			core.MetricDiskIORead.Name:                       {core.LabelResourceID.Key},
   396  			core.MetricDiskIOReadRate.Name:                   {core.LabelResourceID.Key},
   397  			core.MetricDiskIOWrite.Name:                      {core.LabelResourceID.Key},
   398  			core.MetricDiskIOWriteRate.Name:                  {core.LabelResourceID.Key}}
   399  
   400  		for metricName, points := range ts.Metrics {
   401  			md, exists := mdMap[metricName]
   402  			if !exists {
   403  				return fmt.Errorf("unexpected metric %q", metricName)
   404  			}
   405  
   406  			for _, point := range points {
   407  				for _, label := range md.Labels {
   408  					_, exists := point.Labels[label.Key]
   409  					if !exists {
   410  						return fmt.Errorf("metric %q point %v does not contain metric label: %v", metricName, point, label)
   411  					}
   412  				}
   413  			}
   414  
   415  			required := explicitRequirement[metricName]
   416  			for _, label := range required {
   417  				for _, point := range points {
   418  					_, exists := point.Labels[label]
   419  					if !exists {
   420  						return fmt.Errorf("metric %q point %v does not contain metric label: %v", metricName, point, label)
   421  					}
   422  				}
   423  			}
   424  		}
   425  	}
   426  	// Validate that system containers are running on all the nodes.
   427  	// This test could fail if one of the containers was down while the metrics sample was collected.
   428  	for cName, hosts := range actualSystemContainers {
   429  		for _, host := range expectedNodes {
   430  			if _, ok := hosts[host]; !ok {
   431  				return fmt.Errorf("System container %q not found on host: %q - %v", cName, host, actualSystemContainers)
   432  			}
   433  		}
   434  	}
   435  
   436  	if err := expectedItemsExist(expectedPods, actualPods); err != nil {
   437  		return fmt.Errorf("expected pods don't exist %v.\nExpected: %v\nActual:%v", err, expectedPods, actualPods)
   438  	}
   439  	if err := expectedItemsExist(expectedNodes, actualNodes); err != nil {
   440  		return fmt.Errorf("expected nodes don't exist %v.\nExpected: %v\nActual:%v", err, expectedNodes, actualNodes)
   441  	}
   442  
   443  	return nil
   444  }
   445  
   446  func expectedItemsExist(expectedItems []string, actualItems map[string]bool) error {
   447  	for _, item := range expectedItems {
   448  		if _, found := actualItems[item]; !found {
   449  			return fmt.Errorf("missing %s", item)
   450  		}
   451  	}
   452  	return nil
   453  }
   454  
   455  func getErrorCauses(err error) string {
   456  	serr, ok := err.(*apiErrors.StatusError)
   457  	if !ok {
   458  		return ""
   459  	}
   460  	var causes []string
   461  	for _, c := range serr.ErrStatus.Details.Causes {
   462  		causes = append(causes, c.Message)
   463  	}
   464  	return strings.Join(causes, ", ")
   465  }
   466  
   467  var labelSelectorEverything = labels.Everything()
   468  
   469  func getDataFromProxy(fm kubeFramework, svc *kube_v1.Service, url string) ([]byte, error) {
   470  	glog.V(2).Infof("Querying heapster: %s", url)
   471  	return fm.Client().CoreV1().RESTClient().Get().
   472  		Namespace(svc.Namespace).
   473  		Prefix("proxy").
   474  		Resource("services").
   475  		Name(svc.Name).
   476  		Suffix(url).
   477  		Do().Raw()
   478  }
   479  
   480  func getDataFromProxyWithSelector(fm kubeFramework, svc *kube_v1.Service, url string, labelSelector *labels.Selector) ([]byte, error) {
   481  	glog.V(2).Infof("Querying heapster: %s", url)
   482  	return fm.Client().CoreV1().RESTClient().Get().
   483  		Namespace(svc.Namespace).
   484  		Prefix("proxy").
   485  		Resource("services").
   486  		Name(svc.Name).
   487  		Suffix(url).VersionedParams(&metav1.ListOptions{LabelSelector: (*labelSelector).String()}, metav1.ParameterCodec).
   488  		Do().Raw()
   489  }
   490  
   491  func getMetricResultList(fm kubeFramework, svc *kube_v1.Service, url string) (*api_v1.MetricResultList, error) {
   492  	body, err := getDataFromProxy(fm, svc, url)
   493  	if err != nil {
   494  		return nil, err
   495  	}
   496  	var data api_v1.MetricResultList
   497  	if err := json.Unmarshal(body, &data); err != nil {
   498  		glog.V(2).Infof("response body: %v", string(body))
   499  		return nil, err
   500  	}
   501  	if err := checkMetricResultListSanity(&data); err != nil {
   502  		return nil, err
   503  	}
   504  	return &data, nil
   505  }
   506  
   507  func getMetricResult(fm kubeFramework, svc *kube_v1.Service, url string) (*api_v1.MetricResult, error) {
   508  	body, err := getDataFromProxy(fm, svc, url)
   509  	if err != nil {
   510  		return nil, err
   511  	}
   512  	var data api_v1.MetricResult
   513  	if err := json.Unmarshal(body, &data); err != nil {
   514  		glog.V(2).Infof("response body: %v", string(body))
   515  		return nil, err
   516  	}
   517  	if err := checkMetricResultSanity(&data); err != nil {
   518  		return nil, err
   519  	}
   520  	return &data, nil
   521  }
   522  
   523  func getStringResult(fm kubeFramework, svc *kube_v1.Service, url string) ([]string, error) {
   524  	body, err := getDataFromProxy(fm, svc, url)
   525  	if err != nil {
   526  		return nil, err
   527  	}
   528  	var data []string
   529  	if err := json.Unmarshal(body, &data); err != nil {
   530  		glog.V(2).Infof("response body: %v", string(body))
   531  		return nil, err
   532  	}
   533  	if len(data) == 0 {
   534  		return nil, fmt.Errorf("empty string array")
   535  	}
   536  	return data, nil
   537  }
   538  
   539  func checkMetricResultSanity(metrics *api_v1.MetricResult) error {
   540  	bytes, err := json.Marshal(*metrics)
   541  	if err != nil {
   542  		return err
   543  	}
   544  	stringVersion := string(bytes)
   545  
   546  	if len(metrics.Metrics) == 0 {
   547  		return fmt.Errorf("empty metrics: %s", stringVersion)
   548  	}
   549  	// There should be recent metrics in the response.
   550  	if time.Now().Sub(metrics.LatestTimestamp).Seconds() > 120 {
   551  		return fmt.Errorf("corrupted last timestamp: %s", stringVersion)
   552  	}
   553  	// Metrics don't have to be sorted, so the oldest one can be first.
   554  	if time.Now().Sub(metrics.Metrics[0].Timestamp).Hours() > 1 {
   555  		return fmt.Errorf("corrupted timestamp: %s", stringVersion)
   556  	}
   557  	if metrics.Metrics[0].Value > 10000 {
   558  		return fmt.Errorf("value too big: %s", stringVersion)
   559  	}
   560  	return nil
   561  }
   562  
   563  func checkMetricResultListSanity(metrics *api_v1.MetricResultList) error {
   564  	if len(metrics.Items) == 0 {
   565  		return fmt.Errorf("empty metrics")
   566  	}
   567  	for _, item := range metrics.Items {
   568  		err := checkMetricResultSanity(&item)
   569  		if err != nil {
   570  			return err
   571  		}
   572  	}
   573  	return nil
   574  }
   575  
   576  func runModelTest(fm kubeFramework, svc *kube_v1.Service) error {
   577  	podList, err := fm.GetPodsRunningOnNodes()
   578  	if err != nil {
   579  		return err
   580  	}
   581  	if len(podList) == 0 {
   582  		return fmt.Errorf("empty pod list")
   583  	}
   584  	nodeList, err := fm.GetNodeNames()
   585  	if err != nil {
   586  		return err
   587  	}
   588  	if len(nodeList) == 0 {
   589  		return fmt.Errorf("empty node list")
   590  	}
   591  	podNamesList := make([]string, 0, len(podList))
   592  	for _, pod := range podList {
   593  		podNamesList = append(podNamesList, fmt.Sprintf("%s/%s", pod.Namespace, pod.Name))
   594  	}
   595  
   596  	glog.V(0).Infof("Expected pods: %v", podNamesList)
   597  	glog.V(0).Infof("Expected nodes: %v", nodeList)
   598  	allkeys, err := getStringResult(fm, svc, "/api/v1/model/debug/allkeys")
   599  	if err != nil {
   600  		return fmt.Errorf("Failed to get debug information about keys: %v", err)
   601  	}
   602  	glog.V(0).Infof("Available Heapster metric sets: %v", allkeys)
   603  
   604  	metricUrlsToCheck := []string{}
   605  	batchMetricsUrlsToCheck := []string{}
   606  	stringUrlsToCheck := []string{}
   607  
   608  	/* TODO: enable once cluster aggregator is added.
   609  	   metricUrlsToCheck = append(metricUrlsToCheck,
   610  	   fmt.Sprintf("/api/v1/model/metrics/%s", "cpu-usage"),
   611  	)
   612  	*/
   613  
   614  	/* TODO: add once Cluster metrics aggregator is added.
   615  	   "/api/v1/model/metrics",
   616  	   "/api/v1/model/"
   617  	*/
   618  	stringUrlsToCheck = append(stringUrlsToCheck)
   619  
   620  	for _, node := range nodeList {
   621  		metricUrlsToCheck = append(metricUrlsToCheck,
   622  			fmt.Sprintf("/api/v1/model/nodes/%s/metrics/%s", node, "cpu/usage_rate"),
   623  			fmt.Sprintf("/api/v1/model/nodes/%s/metrics/%s", node, "cpu-usage"),
   624  		)
   625  
   626  		stringUrlsToCheck = append(stringUrlsToCheck,
   627  			fmt.Sprintf("/api/v1/model/nodes/%s/metrics", node),
   628  		)
   629  	}
   630  
   631  	for _, pod := range podList {
   632  		containerName := pod.Spec.Containers[0].Name
   633  
   634  		metricUrlsToCheck = append(metricUrlsToCheck,
   635  			fmt.Sprintf("/api/v1/model/namespaces/%s/pods/%s/metrics/%s", pod.Namespace, pod.Name, "cpu/usage_rate"),
   636  			fmt.Sprintf("/api/v1/model/namespaces/%s/pods/%s/metrics/%s", pod.Namespace, pod.Name, "cpu-usage"),
   637  			fmt.Sprintf("/api/v1/model/namespaces/%s/pods/%s/containers/%s/metrics/%s", pod.Namespace, pod.Name, containerName, "cpu/usage_rate"),
   638  			fmt.Sprintf("/api/v1/model/namespaces/%s/pods/%s/containers/%s/metrics/%s", pod.Namespace, pod.Name, containerName, "cpu-usage"),
   639  			fmt.Sprintf("/api/v1/model/namespaces/%s/metrics/%s", pod.Namespace, "cpu/usage_rate"),
   640  			fmt.Sprintf("/api/v1/model/namespaces/%s/metrics/%s", pod.Namespace, "cpu-usage"),
   641  		)
   642  
   643  		batchMetricsUrlsToCheck = append(batchMetricsUrlsToCheck,
   644  			fmt.Sprintf("/api/v1/model/namespaces/%s/pod-list/%s,%s/metrics/%s", pod.Namespace, pod.Name, pod.Name, "cpu/usage_rate"),
   645  			fmt.Sprintf("/api/v1/model/namespaces/%s/pod-list/%s,%s/metrics/%s", pod.Namespace, pod.Name, pod.Name, "cpu-usage"),
   646  		)
   647  
   648  		stringUrlsToCheck = append(stringUrlsToCheck,
   649  			fmt.Sprintf("/api/v1/model/namespaces/%s/metrics", pod.Namespace),
   650  			fmt.Sprintf("/api/v1/model/namespaces/%s/pods/%s/metrics", pod.Namespace, pod.Name),
   651  			fmt.Sprintf("/api/v1/model/namespaces/%s/pods/%s/containers/%s/metrics", pod.Namespace, pod.Name, containerName),
   652  		)
   653  	}
   654  
   655  	for _, url := range metricUrlsToCheck {
   656  		_, err := getMetricResult(fm, svc, url)
   657  		if err != nil {
   658  			return fmt.Errorf("error while querying %s: %v", url, err)
   659  		}
   660  	}
   661  
   662  	for _, url := range batchMetricsUrlsToCheck {
   663  		_, err := getMetricResultList(fm, svc, url)
   664  		if err != nil {
   665  			return fmt.Errorf("error while querying %s: %v", url, err)
   666  		}
   667  	}
   668  
   669  	for _, url := range stringUrlsToCheck {
   670  		_, err := getStringResult(fm, svc, url)
   671  		if err != nil {
   672  			return fmt.Errorf("error while querying %s: %v", url, err)
   673  		}
   674  	}
   675  	return nil
   676  }
   677  
   678  const (
   679  	apiPrefix           = "apis"
   680  	metricsApiGroupName = "metrics.k8s.io"
   681  	metricsApiVersion   = "v1alpha1"
   682  )
   683  
   684  var baseMetricsUrl = fmt.Sprintf("%s/%s/%s", apiPrefix, metricsApiGroupName, metricsApiVersion)
   685  
   686  func checkUsage(res kube_v1.ResourceList) error {
   687  	if _, found := res[kube_v1.ResourceCPU]; !found {
   688  		return fmt.Errorf("Cpu not found")
   689  	}
   690  	if _, found := res[kube_v1.ResourceMemory]; !found {
   691  		return fmt.Errorf("Memory not found")
   692  	}
   693  	return nil
   694  }
   695  
   696  func getPodMetrics(fm kubeFramework, svc *kube_v1.Service, pod kube_v1.Pod) (*metrics_api.PodMetrics, error) {
   697  	url := fmt.Sprintf("%s/namespaces/%s/pods/%s", baseMetricsUrl, pod.Namespace, pod.Name)
   698  	body, err := getDataFromProxy(fm, svc, url)
   699  	if err != nil {
   700  		return nil, err
   701  	}
   702  	var data metrics_api.PodMetrics
   703  	if err := json.Unmarshal(body, &data); err != nil {
   704  		glog.V(2).Infof("response body: %v", string(body))
   705  		return nil, err
   706  	}
   707  	return &data, nil
   708  }
   709  
   710  func getAllPodsInNamespaceMetrics(fm kubeFramework, svc *kube_v1.Service, namespace string) (metrics_api.PodMetricsList, error) {
   711  	url := fmt.Sprintf("%s/namespaces/%s/pods/", baseMetricsUrl, namespace)
   712  	return getPodMetricsList(fm, svc, url, &labelSelectorEverything)
   713  }
   714  
   715  func getAllPodsMetrics(fm kubeFramework, svc *kube_v1.Service) (metrics_api.PodMetricsList, error) {
   716  	url := fmt.Sprintf("%s/pods/", baseMetricsUrl)
   717  	selector := labels.Everything()
   718  	return getPodMetricsList(fm, svc, url, &selector)
   719  }
   720  
   721  func getLabelSelectedPodMetrics(fm kubeFramework, svc *kube_v1.Service, namespace string, labelSelector *labels.Selector) (metrics_api.PodMetricsList, error) {
   722  	url := fmt.Sprintf("%s/namespaces/%s/pods/", baseMetricsUrl, namespace)
   723  	return getPodMetricsList(fm, svc, url, labelSelector)
   724  }
   725  
   726  func getPodMetricsList(fm kubeFramework, svc *kube_v1.Service, url string, labelSelector *labels.Selector) (metrics_api.PodMetricsList, error) {
   727  	body, err := getDataFromProxyWithSelector(fm, svc, url, labelSelector)
   728  	if err != nil {
   729  		return metrics_api.PodMetricsList{}, err
   730  	}
   731  	var data metrics_api.PodMetricsList
   732  	if err := json.Unmarshal(body, &data); err != nil {
   733  		glog.V(2).Infof("response body: %v", string(body))
   734  		return metrics_api.PodMetricsList{}, err
   735  	}
   736  	return data, nil
   737  }
   738  
   739  func checkSinglePodMetrics(metrics *metrics_api.PodMetrics, pod *kube_v1.Pod) error {
   740  	if metrics.Name != pod.Name {
   741  		return fmt.Errorf("Wrong pod name: expected %v, got %v", pod.Name, metrics.Name)
   742  	}
   743  	if metrics.Namespace != pod.Namespace {
   744  		return fmt.Errorf("Wrong pod namespace: expected %v, got %v", pod.Namespace, metrics.Namespace)
   745  	}
   746  	if len(pod.Spec.Containers) != len(metrics.Containers) {
   747  		return fmt.Errorf("Wrong number of containers in returned metrics: expected %v, got %v", len(pod.Spec.Containers), len(metrics.Containers))
   748  	}
   749  	for _, c := range metrics.Containers {
   750  		if err := checkUsage(c.Usage); err != nil {
   751  			return err
   752  		}
   753  	}
   754  	return nil
   755  }
   756  
   757  func getSingleNodeMetrics(fm kubeFramework, svc *kube_v1.Service, node string) (*metrics_api.NodeMetrics, error) {
   758  	url := fmt.Sprintf("%s/nodes/%s", baseMetricsUrl, node)
   759  	body, err := getDataFromProxy(fm, svc, url)
   760  	if err != nil {
   761  		return nil, err
   762  	}
   763  	var data metrics_api.NodeMetrics
   764  	if err := json.Unmarshal(body, &data); err != nil {
   765  		glog.V(2).Infof("response body: %v", string(body))
   766  		return nil, err
   767  	}
   768  	return &data, nil
   769  }
   770  
   771  func getNodeMetricsList(fm kubeFramework, svc *kube_v1.Service, url string, labelSelector *labels.Selector) (metrics_api.NodeMetricsList, error) {
   772  	body, err := getDataFromProxyWithSelector(fm, svc, url, labelSelector)
   773  	if err != nil {
   774  		return metrics_api.NodeMetricsList{}, err
   775  	}
   776  	var data metrics_api.NodeMetricsList
   777  	if err := json.Unmarshal(body, &data); err != nil {
   778  		glog.V(2).Infof("response body: %v", string(body))
   779  		return metrics_api.NodeMetricsList{}, err
   780  	}
   781  	return data, nil
   782  }
   783  
   784  func getLabelSelectedNodeMetrics(fm kubeFramework, svc *kube_v1.Service, labelSelector *labels.Selector) (metrics_api.NodeMetricsList, error) {
   785  	url := fmt.Sprintf("%s/nodes", baseMetricsUrl)
   786  	return getNodeMetricsList(fm, svc, url, labelSelector)
   787  }
   788  
   789  func getAllNodeMetrics(fm kubeFramework, svc *kube_v1.Service) (metrics_api.NodeMetricsList, error) {
   790  	url := fmt.Sprintf("%s/nodes", baseMetricsUrl)
   791  	selector := labels.Everything()
   792  	return getNodeMetricsList(fm, svc, url, &selector)
   793  }
   794  
   795  func runSingleNodeMetricsApiTest(fm kubeFramework, svc *kube_v1.Service) error {
   796  	nodeList, err := fm.GetNodeNames()
   797  	if err != nil {
   798  		return err
   799  	}
   800  	if len(nodeList) == 0 {
   801  		return fmt.Errorf("empty node list")
   802  	}
   803  
   804  	for _, node := range nodeList {
   805  		metrics, err := getSingleNodeMetrics(fm, svc, node)
   806  		if err != nil {
   807  			return err
   808  		}
   809  		if metrics.Name != node {
   810  			return fmt.Errorf("Wrong node name: expected %v, got %v", node, metrics.Name)
   811  		}
   812  		if err := checkUsage(metrics.Usage); err != nil {
   813  			return err
   814  		}
   815  	}
   816  	return nil
   817  }
   818  
   819  func runLabelSelectorNodeMetricsApiTest(fm kubeFramework, svc *kube_v1.Service) error {
   820  	nodeList, err := fm.GetNodes()
   821  	if err != nil {
   822  		return err
   823  	}
   824  	if len(nodeList.Items) == 0 {
   825  		return fmt.Errorf("empty node list")
   826  	}
   827  	labelMap := make(map[string]map[string]kube_v1.Node)
   828  	for _, n := range nodeList.Items {
   829  		for label, value := range n.Labels {
   830  			selector := label + "=" + value
   831  			if _, found := labelMap[selector]; !found {
   832  				labelMap[selector] = make(map[string]kube_v1.Node)
   833  			}
   834  			labelMap[selector][n.Name] = n
   835  		}
   836  	}
   837  
   838  	for selector, nodesWithLabel := range labelMap {
   839  		sel, err := labels.Parse(selector)
   840  		if err != nil {
   841  			return err
   842  		}
   843  		metrics, err := getLabelSelectedNodeMetrics(fm, svc, &sel)
   844  		if err != nil {
   845  			return err
   846  		}
   847  		if len(metrics.Items) != len(nodesWithLabel) {
   848  			return fmt.Errorf("Wrong number of label selected node metrics: expected %v, got %v", len(nodesWithLabel), len(metrics.Items))
   849  		}
   850  		for _, nodeMetric := range metrics.Items {
   851  			node := nodesWithLabel[nodeMetric.Name]
   852  			if nodeMetric.Name != node.Name {
   853  				return fmt.Errorf("Wrong node name: expected %v, got %v", node.Name, nodeMetric.Name)
   854  			}
   855  			if err := checkUsage(nodeMetric.Usage); err != nil {
   856  				return err
   857  			}
   858  		}
   859  	}
   860  	return nil
   861  }
   862  
   863  func runAllNodesMetricsApiTest(fm kubeFramework, svc *kube_v1.Service) error {
   864  	nodeList, err := fm.GetNodeNames()
   865  	if err != nil {
   866  		return err
   867  	}
   868  	if len(nodeList) == 0 {
   869  		return fmt.Errorf("empty node list")
   870  	}
   871  
   872  	nodeNames := sets.NewString(nodeList...)
   873  	metrics, err := getAllNodeMetrics(fm, svc)
   874  	if err != nil {
   875  		return err
   876  	}
   877  
   878  	if len(metrics.Items) != len(nodeList) {
   879  		return fmt.Errorf("Wrong number of all node metrics: expected %v, got %v", len(nodeList), len(metrics.Items))
   880  	}
   881  	for _, nodeMetrics := range metrics.Items {
   882  		if !nodeNames.Has(nodeMetrics.Name) {
   883  			return fmt.Errorf("Unexpected node name: %v, expected one of: %v", nodeMetrics.Name, nodeList)
   884  		}
   885  		if err := checkUsage(nodeMetrics.Usage); err != nil {
   886  			return err
   887  		}
   888  	}
   889  	return nil
   890  }
   891  
   892  func runSinglePodMetricsApiTest(fm kubeFramework, svc *kube_v1.Service) error {
   893  	podList, err := fm.GetAllRunningPods()
   894  	if err != nil {
   895  		return err
   896  	}
   897  	if len(podList) == 0 {
   898  		return fmt.Errorf("empty pod list")
   899  	}
   900  	for _, pod := range podList {
   901  		metrics, err := getPodMetrics(fm, svc, pod)
   902  		if err != nil {
   903  			return err
   904  		}
   905  		err = checkSinglePodMetrics(metrics, &pod)
   906  		if err != nil {
   907  			return err
   908  		}
   909  	}
   910  	return nil
   911  }
   912  
   913  func runAllPodsInNamespaceMetricsApiTest(fm kubeFramework, svc *kube_v1.Service) error {
   914  	podList, err := fm.GetAllRunningPods()
   915  	if err != nil {
   916  		return err
   917  	}
   918  	if len(podList) == 0 {
   919  		return fmt.Errorf("empty pod list")
   920  	}
   921  	nsToPods := make(map[string]map[string]kube_v1.Pod)
   922  	for _, pod := range podList {
   923  		if _, found := nsToPods[pod.Namespace]; !found {
   924  			nsToPods[pod.Namespace] = make(map[string]kube_v1.Pod)
   925  		}
   926  		nsToPods[pod.Namespace][pod.Name] = pod
   927  	}
   928  
   929  	for ns, podMap := range nsToPods {
   930  		metrics, err := getAllPodsInNamespaceMetrics(fm, svc, ns)
   931  		if err != nil {
   932  			return err
   933  		}
   934  
   935  		if len(metrics.Items) != len(nsToPods[ns]) {
   936  			return fmt.Errorf("Wrong number of metrics of all pods in a namespace: expected %v, got %v", len(nsToPods[ns]), len(metrics.Items))
   937  		}
   938  		for _, podMetric := range metrics.Items {
   939  			pod := podMap[podMetric.Name]
   940  			err := checkSinglePodMetrics(&podMetric, &pod)
   941  			if err != nil {
   942  				return err
   943  			}
   944  		}
   945  	}
   946  	return nil
   947  }
   948  
   949  func runAllPodsMetricsApiTest(fm kubeFramework, svc *kube_v1.Service) error {
   950  	podList, err := fm.GetAllRunningPods()
   951  	if err != nil {
   952  		return err
   953  	}
   954  	if len(podList) == 0 {
   955  		return fmt.Errorf("empty pod list")
   956  	}
   957  	pods := make(map[string]kube_v1.Pod)
   958  	for _, p := range podList {
   959  		pods[p.Namespace+"/"+p.Name] = p
   960  	}
   961  
   962  	metrics, err := getAllPodsMetrics(fm, svc)
   963  	if err != nil {
   964  		return err
   965  	}
   966  
   967  	if len(metrics.Items) != len(podList) {
   968  		return fmt.Errorf("Wrong number of all pod metrics: expected %v, got %v", len(podList), len(metrics.Items))
   969  	}
   970  	for _, podMetric := range metrics.Items {
   971  		pod := pods[podMetric.Namespace+"/"+podMetric.Name]
   972  		err := checkSinglePodMetrics(&podMetric, &pod)
   973  		if err != nil {
   974  			return err
   975  		}
   976  	}
   977  	return nil
   978  }
   979  
   980  func runLabelSelectorPodMetricsApiTest(fm kubeFramework, svc *kube_v1.Service) error {
   981  	podList, err := fm.GetAllRunningPods()
   982  	if err != nil {
   983  		return err
   984  	}
   985  	if len(podList) == 0 {
   986  		return fmt.Errorf("empty pod list")
   987  	}
   988  	nsToPods := make(map[string][]kube_v1.Pod)
   989  	for _, pod := range podList {
   990  		nsToPods[pod.Namespace] = append(nsToPods[pod.Namespace], pod)
   991  	}
   992  
   993  	for ns, podsInNamespace := range nsToPods {
   994  		labelMap := make(map[string]map[string]kube_v1.Pod)
   995  		for _, p := range podsInNamespace {
   996  			for label, name := range p.Labels {
   997  				selector := label + "=" + name
   998  				if _, found := labelMap[selector]; !found {
   999  					labelMap[selector] = make(map[string]kube_v1.Pod)
  1000  				}
  1001  				labelMap[selector][p.Name] = p
  1002  			}
  1003  		}
  1004  		for selector, podsWithLabel := range labelMap {
  1005  			sel, err := labels.Parse(selector)
  1006  			if err != nil {
  1007  				return err
  1008  			}
  1009  			metrics, err := getLabelSelectedPodMetrics(fm, svc, ns, &sel)
  1010  			if err != nil {
  1011  				return err
  1012  			}
  1013  			if len(metrics.Items) != len(podsWithLabel) {
  1014  				return fmt.Errorf("Wrong number of label selected pod metrics: expected %v, got %v", len(podsWithLabel), len(metrics.Items))
  1015  			}
  1016  			for _, podMetric := range metrics.Items {
  1017  				pod := podsWithLabel[podMetric.Name]
  1018  				err := checkSinglePodMetrics(&podMetric, &pod)
  1019  				if err != nil {
  1020  					return err
  1021  				}
  1022  			}
  1023  		}
  1024  	}
  1025  	return nil
  1026  }
  1027  
  1028  func apiTest(kubeVersion string, zone string) error {
  1029  	fm, err := newKubeFramework(kubeVersion)
  1030  	if err != nil {
  1031  		return err
  1032  	}
  1033  	if err := buildAndPushDockerImages(fm, zone); err != nil {
  1034  		return err
  1035  	}
  1036  
  1037  	// Create heapster pod and service.
  1038  	svc, rc, err := getHeapsterRcAndSvc(fm)
  1039  	if err != nil {
  1040  		return err
  1041  	}
  1042  	ns := *namespace
  1043  	if err := deleteAll(fm, ns, svc, rc); err != nil {
  1044  		return err
  1045  	}
  1046  	if err := createAll(fm, ns, &svc, &rc); err != nil {
  1047  		return err
  1048  	}
  1049  
  1050  	setupHeapsterServiceAccount(fm)
  1051  	setupHeapsterRBAC(fm)
  1052  
  1053  	if err := fm.WaitUntilPodRunning(ns, rc.Spec.Template.Labels, time.Minute); err != nil {
  1054  		return err
  1055  	}
  1056  	if err := fm.WaitUntilServiceActive(svc, time.Minute); err != nil {
  1057  		return err
  1058  	}
  1059  	testFuncs := []func() error{
  1060  		func() error {
  1061  			glog.V(2).Infof("Heapster metric export test...")
  1062  			err := runMetricExportTest(fm, svc)
  1063  			if err == nil {
  1064  				glog.V(2).Infof("Heapster metric export test: OK")
  1065  			} else {
  1066  				glog.V(2).Infof("Heapster metric export test: error: %v", err)
  1067  			}
  1068  			return err
  1069  		},
  1070  		func() error {
  1071  			glog.V(2).Infof("Model test")
  1072  			err := runModelTest(fm, svc)
  1073  			if err == nil {
  1074  				glog.V(2).Infof("Model test: OK")
  1075  			} else {
  1076  				glog.V(2).Infof("Model test: error: %v", err)
  1077  			}
  1078  			return err
  1079  		},
  1080  		func() error {
  1081  			glog.V(2).Infof("Metrics API test - single pod")
  1082  			err := runSinglePodMetricsApiTest(fm, svc)
  1083  			if err == nil {
  1084  				glog.V(2).Infof("Metrics API test - single pod: OK")
  1085  			} else {
  1086  				glog.V(2).Infof("Metrics API test - single pod: error: %v", err)
  1087  			}
  1088  			return err
  1089  		},
  1090  		func() error {
  1091  			glog.V(2).Infof("Metrics API test - All pods in a namespace")
  1092  			err := runAllPodsInNamespaceMetricsApiTest(fm, svc)
  1093  			if err == nil {
  1094  				glog.V(2).Infof("Metrics API test - All pods in a namespace: OK")
  1095  			} else {
  1096  				glog.V(2).Infof("Metrics API test - All pods in a namespace: error: %v", err)
  1097  			}
  1098  			return err
  1099  		},
  1100  		func() error {
  1101  			glog.V(2).Infof("Metrics API test - all pods")
  1102  			err := runAllPodsMetricsApiTest(fm, svc)
  1103  			if err == nil {
  1104  				glog.V(2).Infof("Metrics API test - all pods: OK")
  1105  			} else {
  1106  				glog.V(2).Infof("Metrics API test - all pods: error: %v", err)
  1107  			}
  1108  			return err
  1109  		},
  1110  		func() error {
  1111  			glog.V(2).Infof("Metrics API test - label selector for pods")
  1112  			err := runLabelSelectorPodMetricsApiTest(fm, svc)
  1113  			if err == nil {
  1114  				glog.V(2).Infof("Metrics API test - label selector for pods: OK")
  1115  			} else {
  1116  				glog.V(2).Infof("Metrics API test - label selector for pods: error: %v", err)
  1117  			}
  1118  			return err
  1119  		},
  1120  		func() error {
  1121  			glog.V(2).Infof("Metrics API test - single node")
  1122  			err := runSingleNodeMetricsApiTest(fm, svc)
  1123  			if err == nil {
  1124  				glog.V(2).Infof("Metrics API test - single node: OK")
  1125  			} else {
  1126  				glog.V(2).Infof("Metrics API test - single node: error: %v", err)
  1127  			}
  1128  			return err
  1129  		},
  1130  		func() error {
  1131  			glog.V(2).Infof("Metrics API test - label selector for nodes")
  1132  			err := runLabelSelectorNodeMetricsApiTest(fm, svc)
  1133  			if err == nil {
  1134  				glog.V(2).Infof("Metrics API test - label selector for nodes: OK")
  1135  			} else {
  1136  				glog.V(2).Infof("Metrics API test - label selector for nodes: error: %v", err)
  1137  			}
  1138  			return err
  1139  		},
  1140  		func() error {
  1141  			glog.V(2).Infof("Metrics API test - all nodes")
  1142  			err := runAllNodesMetricsApiTest(fm, svc)
  1143  			if err == nil {
  1144  				glog.V(2).Infof("Metrics API test - all nodes: OK")
  1145  			} else {
  1146  				glog.V(2).Infof("Metrics API test - all nodes: error: %v", err)
  1147  			}
  1148  			return err
  1149  		},
  1150  	}
  1151  	attempts := *maxRetries
  1152  	glog.Infof("Starting tests")
  1153  	for {
  1154  		var err error
  1155  		for _, testFunc := range testFuncs {
  1156  			if err = testFunc(); err != nil {
  1157  				break
  1158  			}
  1159  		}
  1160  		if *runForever {
  1161  			continue
  1162  		}
  1163  		if err == nil {
  1164  			glog.V(2).Infof("All tests passed.")
  1165  			break
  1166  		}
  1167  		if attempts == 0 {
  1168  			glog.V(2).Info("Too many attempts.")
  1169  			return err
  1170  		}
  1171  		glog.V(2).Infof("Some tests failed. Retrying.")
  1172  		attempts--
  1173  		time.Sleep(time.Second * 10)
  1174  	}
  1175  	deleteAll(fm, ns, svc, rc)
  1176  	removeHeapsterImage(fm, zone)
  1177  	return nil
  1178  }
  1179  
  1180  func runApiTest() error {
  1181  	tempDir, err := ioutil.TempDir("", "deploy")
  1182  	if err != nil {
  1183  		return nil
  1184  	}
  1185  	defer os.RemoveAll(tempDir)
  1186  	if *kubeVersions == "" {
  1187  		return apiTest("", *testZone)
  1188  	}
  1189  	kubeVersionsList := strings.Split(*kubeVersions, ",")
  1190  	for _, kubeVersion := range kubeVersionsList {
  1191  		if err := apiTest(kubeVersion, *testZone); err != nil {
  1192  			return err
  1193  		}
  1194  	}
  1195  	return nil
  1196  }
  1197  
  1198  func TestHeapster(t *testing.T) {
  1199  	if testing.Short() {
  1200  		t.Skip("skipping heapster kubernetes integration test.")
  1201  	}
  1202  	require.NoError(t, runApiTest())
  1203  }