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 }