github.com/openshift/installer@v1.4.17/pkg/quota/gcp/usage.go (about)

     1  package gcp
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	monitoring "cloud.google.com/go/monitoring/apiv3/v2"
     9  	"cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
    10  	googlepb "github.com/golang/protobuf/ptypes/timestamp"
    11  	"github.com/pkg/errors"
    12  	"google.golang.org/api/iterator"
    13  	"google.golang.org/genproto/googleapis/api/metric"
    14  )
    15  
    16  // loadUsage loads the usage from `consumer_quota` metric type for the project. It pulls metric data for last hour and
    17  // and the uses the latest data point as the usage value for the specific metric type.
    18  func loadUsage(ctx context.Context, client *monitoring.MetricClient, project string) ([]record, error) {
    19  	req := &monitoringpb.ListTimeSeriesRequest{
    20  		Name:   fmt.Sprintf("projects/%s", project),
    21  		Filter: fmt.Sprintf(`metric.type = "serviceruntime.googleapis.com/quota/allocation/usage" AND resource.type = "consumer_quota" AND project = "%s"`, project),
    22  		Interval: &monitoringpb.TimeInterval{
    23  			EndTime: &googlepb.Timestamp{
    24  				Seconds: time.Now().Add(-5 * time.Minute).Unix(),
    25  			},
    26  			StartTime: &googlepb.Timestamp{
    27  				Seconds: time.Now().Add(-1 * time.Hour).Unix(),
    28  			},
    29  		},
    30  	}
    31  
    32  	var usages []record
    33  	it := client.ListTimeSeries(ctx, req)
    34  	for {
    35  		resp, err := it.Next()
    36  		if errors.Is(err, iterator.Done) {
    37  			break
    38  		}
    39  		if err != nil {
    40  			return usages, errors.Wrap(err, "failed to list quota/allocation/usage timeseries")
    41  		}
    42  		usage, err := latestRecord(resp)
    43  		if err != nil {
    44  			return usages, errors.Wrap(err, "failed to load usage from timeseries")
    45  		}
    46  		usages = append(usages, usage)
    47  	}
    48  	return usages, nil
    49  }
    50  
    51  // latestRecord find the latest data point for the timeseries and returns that as the usage for the metric type.
    52  // Based on https://cloud.google.com/monitoring/api/ref_v3/rest/v3/TimeSeries and definition of the points API
    53  // "The data points of this time series. When listing time series, points are returned in reverse time order.",
    54  // The latestRecord returns the first element of the points as the usage value. In case the points list is empty it
    55  // returns 0 as the usage value.
    56  func latestRecord(ts *monitoringpb.TimeSeries) (record, error) {
    57  	service, ok := ts.GetResource().GetLabels()["service"]
    58  	if !ok {
    59  		return record{}, errors.Errorf("serivce not found for timeseries, actual label %s", ts.GetResource().GetLabels())
    60  	}
    61  	name, ok := ts.GetMetric().Labels["quota_metric"]
    62  	if !ok {
    63  		return record{}, errors.New("no name found for timeseries")
    64  	}
    65  	location, ok := ts.GetResource().GetLabels()["location"]
    66  	if !ok {
    67  		return record{}, errors.Errorf("location not found for timeseries, actual label %s", ts.GetResource().GetLabels())
    68  	}
    69  	if ts.GetValueType() != metric.MetricDescriptor_INT64 {
    70  		return record{}, errors.Errorf("invalid value type for timeseries, was %s", ts.GetValueType())
    71  	}
    72  	value := int64(0)
    73  	if points := ts.GetPoints(); len(points) > 0 {
    74  		value = points[0].GetValue().GetInt64Value()
    75  	}
    76  	return record{
    77  		Service:  service,
    78  		Name:     name,
    79  		Location: location,
    80  		Value:    value,
    81  	}, nil
    82  }