github.com/google/cloudprober@v0.11.3/probes/probes.go (about) 1 // Copyright 2017 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 probes provides an interface to initialize probes using prober config. 17 */ 18 package probes 19 20 import ( 21 "context" 22 "fmt" 23 "regexp" 24 "sync" 25 26 "github.com/golang/protobuf/proto" 27 "github.com/google/cloudprober/metrics" 28 "github.com/google/cloudprober/probes/dns" 29 "github.com/google/cloudprober/probes/external" 30 grpcprobe "github.com/google/cloudprober/probes/grpc" 31 httpprobe "github.com/google/cloudprober/probes/http" 32 "github.com/google/cloudprober/probes/options" 33 "github.com/google/cloudprober/probes/ping" 34 configpb "github.com/google/cloudprober/probes/proto" 35 "github.com/google/cloudprober/probes/udp" 36 "github.com/google/cloudprober/probes/udplistener" 37 "github.com/google/cloudprober/web/formatutils" 38 ) 39 40 var ( 41 userDefinedProbes = make(map[string]Probe) 42 userDefinedProbesMu sync.Mutex 43 extensionMap = make(map[int]func() Probe) 44 extensionMapMu sync.Mutex 45 ) 46 47 func runOnThisHost(runOn string, hostname string) (bool, error) { 48 if runOn == "" { 49 return true, nil 50 } 51 r, err := regexp.Compile(runOn) 52 if err != nil { 53 return false, err 54 } 55 return r.MatchString(hostname), nil 56 } 57 58 // Probe interface represents a probe. 59 // 60 // A probe is initilized using the Init() method. Init takes the name of the 61 // probe and probe options. 62 // 63 // Start() method starts the probe. Start is not expected to return for the 64 // lifetime of the prober. It takes a data channel that it writes the probe 65 // results on. Actual publishing of these results is handled by cloudprober 66 // itself. 67 type Probe interface { 68 Init(name string, opts *options.Options) error 69 Start(ctx context.Context, dataChan chan *metrics.EventMetrics) 70 } 71 72 // ProbeInfo encapsulates the probe and associated information. 73 type ProbeInfo struct { 74 Probe 75 ProbeDef *configpb.ProbeDef // Full probe definition 76 Options *options.Options 77 Name string 78 Type string 79 Interval string 80 Timeout string 81 TargetsDesc string 82 LatencyDistLB string 83 LatencyUnit string 84 ProbeConf string 85 SourceIP string 86 } 87 88 func getExtensionProbe(p *configpb.ProbeDef) (Probe, interface{}, error) { 89 extensions, err := proto.ExtensionDescs(p) 90 if err != nil { 91 return nil, nil, fmt.Errorf("error getting extensions from the probe config (%s): %v", p.String(), err) 92 } 93 if len(extensions) != 1 { 94 return nil, nil, fmt.Errorf("there should be exactly one extension in the probe config (%s), got %d extensions", p.String(), len(extensions)) 95 } 96 desc := extensions[0] 97 value, err := proto.GetExtension(p, desc) 98 if err != nil { 99 return nil, nil, err 100 } 101 extensionMapMu.Lock() 102 defer extensionMapMu.Unlock() 103 newProbeFunc, ok := extensionMap[int(desc.Field)] 104 if !ok { 105 return nil, nil, fmt.Errorf("no probes registered for the extension: %d", desc.Field) 106 } 107 return newProbeFunc(), value, nil 108 } 109 110 // CreateProbe creates a new probe. 111 func CreateProbe(p *configpb.ProbeDef, opts *options.Options) (*ProbeInfo, error) { 112 probe, probeConf, err := initProbe(p, opts) 113 if err != nil { 114 return nil, err 115 } 116 117 probeInfo := &ProbeInfo{ 118 Probe: probe, 119 ProbeDef: p, 120 Options: opts, 121 Name: p.GetName(), 122 Type: p.GetType().String(), 123 Interval: opts.Interval.String(), 124 Timeout: opts.Timeout.String(), 125 TargetsDesc: p.Targets.String(), 126 LatencyUnit: opts.LatencyUnit.String(), 127 ProbeConf: formatutils.ConfToString(probeConf), 128 } 129 130 if opts.LatencyDist != nil { 131 probeInfo.LatencyDistLB = fmt.Sprintf("%v", opts.LatencyDist.Data().LowerBounds) 132 } 133 if opts.SourceIP != nil { 134 probeInfo.SourceIP = opts.SourceIP.String() 135 } 136 return probeInfo, nil 137 } 138 139 func initProbe(p *configpb.ProbeDef, opts *options.Options) (probe Probe, probeConf interface{}, err error) { 140 switch p.GetType() { 141 case configpb.ProbeDef_PING: 142 probe = &ping.Probe{} 143 probeConf = p.GetPingProbe() 144 case configpb.ProbeDef_HTTP: 145 probe = &httpprobe.Probe{} 146 probeConf = p.GetHttpProbe() 147 case configpb.ProbeDef_DNS: 148 probe = &dns.Probe{} 149 probeConf = p.GetDnsProbe() 150 case configpb.ProbeDef_EXTERNAL: 151 probe = &external.Probe{} 152 probeConf = p.GetExternalProbe() 153 case configpb.ProbeDef_UDP: 154 probe = &udp.Probe{} 155 probeConf = p.GetUdpProbe() 156 case configpb.ProbeDef_UDP_LISTENER: 157 probe = &udplistener.Probe{} 158 probeConf = p.GetUdpListenerProbe() 159 case configpb.ProbeDef_GRPC: 160 probe = &grpcprobe.Probe{} 161 probeConf = p.GetGrpcProbe() 162 case configpb.ProbeDef_EXTENSION: 163 probe, probeConf, err = getExtensionProbe(p) 164 if err != nil { 165 return 166 } 167 case configpb.ProbeDef_USER_DEFINED: 168 userDefinedProbesMu.Lock() 169 defer userDefinedProbesMu.Unlock() 170 probe = userDefinedProbes[p.GetName()] 171 if probe == nil { 172 err = fmt.Errorf("unregistered user defined probe: %s", p.GetName()) 173 return 174 } 175 probeConf = p.GetUserDefinedProbe() 176 default: 177 err = fmt.Errorf("unknown probe type: %s", p.GetType()) 178 return 179 } 180 181 opts.ProbeConf = probeConf 182 err = probe.Init(p.GetName(), opts) 183 return 184 } 185 186 // RegisterUserDefined allows you to register a user defined probe with 187 // cloudprober. 188 // Example usage: 189 // import ( 190 // "github.com/google/cloudprober" 191 // "github.com/google/cloudprober/probes" 192 // ) 193 // 194 // p := &FancyProbe{} 195 // probes.RegisterUserDefined("fancy_probe", p) 196 // pr, err := cloudprober.InitFromConfig(*configFile) 197 // if err != nil { 198 // log.Exitf("Error initializing cloudprober. Err: %v", err) 199 // } 200 func RegisterUserDefined(name string, probe Probe) { 201 userDefinedProbesMu.Lock() 202 defer userDefinedProbesMu.Unlock() 203 userDefinedProbes[name] = probe 204 } 205 206 // RegisterProbeType registers a new probe-type. New probe types are integrated 207 // with the config subsystem using the protobuf extensions. 208 // 209 // TODO(manugarg): Add a full example of using extensions. 210 func RegisterProbeType(extensionFieldNo int, newProbeFunc func() Probe) { 211 extensionMapMu.Lock() 212 defer extensionMapMu.Unlock() 213 extensionMap[extensionFieldNo] = newProbeFunc 214 }