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  }