Skip to content

Commit

Permalink
Merge pull request #2829 from justinsb/mockgcp_monitoriningmetricdesc…
Browse files Browse the repository at this point in the history
…riptor

mockgcp: support for MonitoringMetricDescriptor
  • Loading branch information
google-oss-prow[bot] authored Oct 18, 2024
2 parents 964049c + a5e88e3 commit bcc5c54
Show file tree
Hide file tree
Showing 5 changed files with 472 additions and 1 deletion.
1 change: 1 addition & 0 deletions config/tests/samples/create/harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ func MaybeSkip(t *testing.T, name string, resources []*unstructured.Unstructured
case schema.GroupKind{Group: "monitoring.cnrm.cloud.google.com", Kind: "MonitoringAlertPolicy"}:
case schema.GroupKind{Group: "monitoring.cnrm.cloud.google.com", Kind: "MonitoringDashboard"}:
case schema.GroupKind{Group: "monitoring.cnrm.cloud.google.com", Kind: "MonitoringGroup"}:
case schema.GroupKind{Group: "monitoring.cnrm.cloud.google.com", Kind: "MonitoringMetricDescriptor"}:
case schema.GroupKind{Group: "monitoring.cnrm.cloud.google.com", Kind: "MonitoringMonitoredProject"}:
case schema.GroupKind{Group: "monitoring.cnrm.cloud.google.com", Kind: "MonitoringNotificationChannel"}:
case schema.GroupKind{Group: "monitoring.cnrm.cloud.google.com", Kind: "MonitoringService"}:
Expand Down
188 changes: 188 additions & 0 deletions mockgcp/mockmonitoring/metricdescriptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// Copyright 2024 Google LLC
//
// 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 mockmonitoring

import (
"context"
"sort"
"strings"
"time"

"github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/common/projects"
pb "github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/generated/mockgcp/monitoring/v3"
"github.com/golang/protobuf/ptypes/empty"
"google.golang.org/genproto/googleapis/api"
metric "google.golang.org/genproto/googleapis/api/metric"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/klog/v2"
)

type metricService struct {
*MockService
pb.UnimplementedMetricServiceServer
}

func (s *metricService) GetMetricDescriptor(ctx context.Context, req *pb.GetMetricDescriptorRequest) (*metric.MetricDescriptor, error) {
name, err := s.parseMetricDescriptorName(req.GetName())
if err != nil {
return nil, err
}

fqn := name.String()

obj := &metric.MetricDescriptor{}
if err := s.storage.Get(ctx, fqn, obj); err != nil {
if status.Code(err) == codes.NotFound {
return nil, status.Errorf(codes.NotFound, "Could not find descriptor for metric '%s'.", name.MetricID)
}
return nil, err
}

// returned object does not include launchStage or metadata
retObj := ProtoClone(obj)
retObj.LaunchStage = api.LaunchStage_LAUNCH_STAGE_UNSPECIFIED
retObj.Metadata = nil

return retObj, nil
}

func populateDefaultsForMetricDescriptor(obj *metric.MetricDescriptor) {
if obj.MonitoredResourceTypes == nil {
obj.MonitoredResourceTypes = []string{
"aws_ec2_instance",
"aws_lambda_function",
"aws_sqs_queue",
"baremetalsolution.googleapis.com/Instance",
"cloud_composer_environment",
"cloud_composer_workflow",
"cloud_dataproc_batch",
"dataflow_job",
"gae_instance",
"gce_instance",
"generic_node",
"generic_task",
"gke_container",
"global",
"k8s_cluster",
"k8s_container",
"k8s_node",
"k8s_pod",
"k8s_service",
"prometheus_target",
}
}
}

func (s *metricService) CreateMetricDescriptor(ctx context.Context, req *pb.CreateMetricDescriptorRequest) (*metric.MetricDescriptor, error) {
metricDescriptorID := req.GetMetricDescriptor().GetType()
if metricDescriptorID == "" {
return nil, status.Errorf(codes.InvalidArgument, "type is required")
}

reqName := req.GetName() + "/metricDescriptors/" + metricDescriptorID
name, err := s.parseMetricDescriptorName(reqName)
if err != nil {
return nil, err
}

fqn := name.String()

obj := ProtoClone(req.MetricDescriptor)
obj.Name = fqn

// Creation is actually async - but without an LRO (!!!)
go func() {
ctx := context.Background()
log := klog.FromContext(ctx)

time.Sleep(1 * time.Second)

obj = ProtoClone(obj)

populateDefaultsForMetricDescriptor(obj)

// Labels are reordered
sort.Slice(obj.Labels, func(i, j int) bool {
return obj.Labels[i].Key < obj.Labels[j].Key
})

if err := s.storage.Create(ctx, fqn, obj); err != nil {
log.Error(err, "error creating metricDescriptor")
}
}()

return obj, nil
}

func (s *metricService) DeleteMetricDescriptor(ctx context.Context, req *pb.DeleteMetricDescriptorRequest) (*empty.Empty, error) {
name, err := s.parseMetricDescriptorName(req.Name)
if err != nil {
return nil, err
}

fqn := name.String()

// Deletion is actually async - but without an LRO (!!!)
go func() {
ctx := context.Background()
log := klog.FromContext(ctx)

time.Sleep(10 * time.Second)
deleted := &metric.MetricDescriptor{}
if err := s.storage.Delete(ctx, fqn, deleted); err != nil {
log.Error(err, "error deleting metricDescriptor")
}
}()

return &empty.Empty{}, nil
}

type metricDescriptorName struct {
Project *projects.ProjectData
MetricID string
}

func (n *metricDescriptorName) String() string {
return "projects/" + n.Project.ID + "/metricDescriptors/" + n.MetricID
}

// parseMetricDescriptorName parses a string into a metricDescriptorName.
// The format is:
//
// projects/[PROJECT_ID_OR_NUMBER]/metricDescriptors/[METRIC_ID]
//
// An example value of `[METRIC_ID]` is
// `"compute.googleapis.com/instance/disk/read_bytes_count"`.
func (s *MockService) parseMetricDescriptorName(name string) (*metricDescriptorName, error) {
tokens := strings.Split(name, "/")

// Note: this is unusual - the ID can contain slashes (which are our delimiter)
if len(tokens) >= 4 && tokens[0] == "projects" && tokens[2] == "metricDescriptors" {
project, err := s.Projects.GetProjectByID(tokens[1])
if err != nil {
return nil, err
}

name := &metricDescriptorName{
Project: project,
MetricID: strings.Join(tokens[3:], "/"),
}

return name, nil
} else {
return nil, status.Errorf(codes.InvalidArgument, "name %q is not valid", name)
}
}
2 changes: 2 additions & 0 deletions mockgcp/mockmonitoring/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func (s *MockService) ExpectedHosts() []string {
func (s *MockService) Register(grpcServer *grpc.Server) {
monitoringpb.RegisterAlertPolicyServiceServer(grpcServer, &AlertPolicyService{MockService: s})
monitoringpb.RegisterGroupServiceServer(grpcServer, &GroupService{MockService: s})
monitoringpb.RegisterMetricServiceServer(grpcServer, &metricService{MockService: s})
monitoringpb.RegisterNotificationChannelServiceServer(grpcServer, &NotificationChannelService{MockService: s})
monitoringpb.RegisterServiceMonitoringServiceServer(grpcServer, &serviceMonitoringService{MockService: s})
monitoringpb.RegisterUptimeCheckServiceServer(grpcServer, &UptimeCheckService{MockService: s})
Expand All @@ -66,6 +67,7 @@ func (s *MockService) NewHTTPMux(ctx context.Context, conn *grpc.ClientConn) (ht
mux, err := httpmux.NewServeMux(ctx, conn, httpmux.Options{},
monitoringpb.RegisterAlertPolicyServiceHandler,
monitoringpb.RegisterGroupServiceHandler,
monitoringpb.RegisterMetricServiceHandler,
monitoringpb.RegisterNotificationChannelServiceHandler,
monitoringpb.RegisterServiceMonitoringServiceHandler,
monitoringpb.RegisterUptimeCheckServiceHandler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
annotations:
cnrm.cloud.google.com/management-conflict-prevention-policy: none
cnrm.cloud.google.com/mutable-but-unreadable-fields: '{}'
cnrm.cloud.google.com/state-into-spec: merge
cnrm.cloud.google.com/state-into-spec: absent
finalizers:
- cnrm.cloud.google.com/finalizer
- cnrm.cloud.google.com/deletion-defender
Expand Down
Loading

0 comments on commit bcc5c54

Please sign in to comment.