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 }