github.com/google/cloudprober@v0.11.3/rds/gcp/gcp.go (about)

     1  // Copyright 2017-2020 The Cloudprober Authors.
     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  /*
    16  Package gcp implements a GCP (Google Compute Platform) resources provider for
    17  ResourceDiscovery server.
    18  
    19  See ResourceTypes variable for the list of supported resource types.
    20  
    21  GCP provider is configured through a protobuf based config file
    22  (proto/config.proto). Example config:
    23  
    24  	{
    25  		project_id: 'test-project-1'
    26  		project_id: 'test-project-2'
    27  		gce_instances {}
    28  	}
    29  
    30  */
    31  package gcp
    32  
    33  import (
    34  	"errors"
    35  	"fmt"
    36  	"strings"
    37  
    38  	"cloud.google.com/go/compute/metadata"
    39  	"github.com/golang/protobuf/proto"
    40  	"github.com/google/cloudprober/logger"
    41  	configpb "github.com/google/cloudprober/rds/gcp/proto"
    42  	pb "github.com/google/cloudprober/rds/proto"
    43  	serverconfigpb "github.com/google/cloudprober/rds/server/proto"
    44  )
    45  
    46  // DefaultProviderID is the povider id to use for this provider if a provider
    47  // id is not configured explicitly.
    48  const DefaultProviderID = "gcp"
    49  
    50  // ResourceTypes declares resource types supported by the GCP provider.
    51  // Note that "rtc_variables" resource type is deprecated now and will soon be
    52  // removed.
    53  var ResourceTypes = struct {
    54  	GCEInstances, ForwardingRules, RTCVariables, PubsubMessages string
    55  }{
    56  	"gce_instances",
    57  	"forwarding_rules",
    58  	"rtc_variables",
    59  	"pubsub_messages",
    60  }
    61  
    62  var resourcePathTmpl = "<resource_type>[/<project-id>]"
    63  
    64  type lister interface {
    65  	listResources(req *pb.ListResourcesRequest) ([]*pb.Resource, error)
    66  }
    67  
    68  // Provider implements a GCP provider for a ResourceDiscovery server.
    69  type Provider struct {
    70  	localProject string
    71  	projects     []string
    72  	listers      map[string]map[string]lister
    73  }
    74  
    75  func (p *Provider) listerForResourcePath(resourcePath string) (lister, error) {
    76  	tok := strings.SplitN(resourcePath, "/", 2)
    77  	resType := tok[0]
    78  
    79  	var project string
    80  	if len(tok) == 2 {
    81  		project = tok[1]
    82  	}
    83  
    84  	if project == "" {
    85  		// If project is not specified, use the first supported project.
    86  		project = p.projects[0]
    87  	}
    88  
    89  	projectListers := p.listers[project]
    90  	if projectListers == nil {
    91  		return nil, fmt.Errorf("no listers found for the project: %s", project)
    92  	}
    93  
    94  	lr := projectListers[resType]
    95  	if lr == nil {
    96  		return nil, fmt.Errorf("unknown resource type: %s", resType)
    97  	}
    98  	return lr, nil
    99  }
   100  
   101  // ListResources returns the list of resources based on the given request.
   102  func (p *Provider) ListResources(req *pb.ListResourcesRequest) (*pb.ListResourcesResponse, error) {
   103  	lr, err := p.listerForResourcePath(req.GetResourcePath())
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  
   108  	resources, err := lr.listResources(req)
   109  	return &pb.ListResourcesResponse{Resources: resources}, err
   110  }
   111  
   112  func initGCPProject(project string, c *configpb.ProviderConfig, l *logger.Logger) (map[string]lister, error) {
   113  	projectLister := make(map[string]lister)
   114  
   115  	// Enable GCE instances lister if configured.
   116  	if c.GetGceInstances() != nil {
   117  		lr, err := newGCEInstancesLister(project, c.GetApiVersion(), c.GetGceInstances(), l)
   118  		if err != nil {
   119  			return nil, err
   120  		}
   121  		projectLister[ResourceTypes.GCEInstances] = lr
   122  	}
   123  
   124  	// Enable forwarding rules lister if configured.
   125  	if c.GetForwardingRules() != nil {
   126  		lr, err := newForwardingRulesLister(project, c.GetApiVersion(), c.GetForwardingRules(), l)
   127  		if err != nil {
   128  			return nil, err
   129  		}
   130  		projectLister[ResourceTypes.ForwardingRules] = lr
   131  	}
   132  
   133  	// Enable RTC variables lister if configured.
   134  	if c.GetPubsubMessages() != nil {
   135  		lr, err := newPubSubMsgsLister(project, c.GetPubsubMessages(), l)
   136  		if err != nil {
   137  			return nil, err
   138  		}
   139  		projectLister[ResourceTypes.PubsubMessages] = lr
   140  	}
   141  
   142  	// Enable RTC variables lister if configured.
   143  	if c.GetRtcVariables() != nil {
   144  		lr, err := newRTCVariablesLister(project, c.GetApiVersion(), c.GetRtcVariables(), l)
   145  		if err != nil {
   146  			return nil, err
   147  		}
   148  		projectLister[ResourceTypes.RTCVariables] = lr
   149  	}
   150  
   151  	return projectLister, nil
   152  }
   153  
   154  // New creates a GCP provider for RDS server, based on the provided config.
   155  func New(c *configpb.ProviderConfig, l *logger.Logger) (*Provider, error) {
   156  	projects := c.GetProject()
   157  	if len(projects) == 0 {
   158  		if !metadata.OnGCE() {
   159  			return nil, errors.New("rds.gcp.New(): project not configured and not running on GCE")
   160  		}
   161  
   162  		project, err := metadata.ProjectID()
   163  		if err != nil {
   164  			return nil, fmt.Errorf("rds.gcp.New(): error getting the local project ID on GCE: %v", err)
   165  		}
   166  
   167  		projects = append(projects, project)
   168  	}
   169  
   170  	p := &Provider{
   171  		projects: projects,
   172  		listers:  make(map[string]map[string]lister),
   173  	}
   174  
   175  	for _, project := range projects {
   176  		projectLister, err := initGCPProject(project, c, l)
   177  		if err != nil {
   178  			return nil, err
   179  		}
   180  		p.listers[project] = projectLister
   181  	}
   182  
   183  	return p, nil
   184  }
   185  
   186  // DefaultProviderConfig is a convenience function that builds and returns a
   187  // basic GCP provider config based on the given parameters.
   188  func DefaultProviderConfig(projects []string, resTypes map[string]string, reEvalSec int, apiVersion string) *serverconfigpb.Provider {
   189  	c := &configpb.ProviderConfig{
   190  		Project:    projects,
   191  		ApiVersion: proto.String(apiVersion),
   192  	}
   193  
   194  	for k, v := range resTypes {
   195  		switch k {
   196  		case ResourceTypes.GCEInstances:
   197  			c.GceInstances = &configpb.GCEInstances{
   198  				ReEvalSec: proto.Int32(int32(reEvalSec)),
   199  			}
   200  
   201  		case ResourceTypes.ForwardingRules:
   202  			c.ForwardingRules = &configpb.ForwardingRules{
   203  				ReEvalSec: proto.Int32(int32(reEvalSec)),
   204  			}
   205  
   206  		case ResourceTypes.RTCVariables:
   207  			c.RtcVariables = &configpb.RTCVariables{
   208  				RtcConfig: []*configpb.RTCVariables_RTCConfig{
   209  					{
   210  						Name:      proto.String(v),
   211  						ReEvalSec: proto.Int32(int32(reEvalSec)),
   212  					},
   213  				},
   214  			}
   215  
   216  		case ResourceTypes.PubsubMessages:
   217  			c.PubsubMessages = &configpb.PubSubMessages{
   218  				Subscription: []*configpb.PubSubMessages_Subscription{
   219  					{
   220  						TopicName: proto.String(v),
   221  					},
   222  				},
   223  			}
   224  		}
   225  	}
   226  
   227  	return &serverconfigpb.Provider{
   228  		Id:     proto.String(DefaultProviderID),
   229  		Config: &serverconfigpb.Provider_GcpConfig{GcpConfig: c},
   230  	}
   231  }