github.com/google/cloudprober@v0.11.3/probes/options/options.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 options provides a shared interface to common probe options.
    17  */
    18  package options
    19  
    20  import (
    21  	"fmt"
    22  	"net"
    23  	"time"
    24  
    25  	"github.com/google/cloudprober/common/iputils"
    26  	"github.com/google/cloudprober/logger"
    27  	"github.com/google/cloudprober/metrics"
    28  	configpb "github.com/google/cloudprober/probes/proto"
    29  	"github.com/google/cloudprober/targets"
    30  	"github.com/google/cloudprober/targets/endpoint"
    31  	targetspb "github.com/google/cloudprober/targets/proto"
    32  	"github.com/google/cloudprober/validators"
    33  )
    34  
    35  // Options encapsulates common probe options.
    36  type Options struct {
    37  	Targets             targets.Targets
    38  	Interval, Timeout   time.Duration
    39  	Logger              *logger.Logger
    40  	ProbeConf           interface{} // Probe-type specific config
    41  	LatencyDist         *metrics.Distribution
    42  	LatencyUnit         time.Duration
    43  	Validators          []*validators.Validator
    44  	SourceIP            net.IP
    45  	IPVersion           int
    46  	StatsExportInterval time.Duration
    47  	LogMetrics          func(*metrics.EventMetrics)
    48  	AdditionalLabels    []*AdditionalLabel
    49  }
    50  
    51  const defaultStatsExtportIntv = 10 * time.Second
    52  
    53  func defaultStatsExportInterval(p *configpb.ProbeDef, opts *Options) time.Duration {
    54  	minIntv := opts.Interval
    55  	if opts.Timeout > opts.Interval {
    56  		minIntv = opts.Timeout
    57  	}
    58  
    59  	// UDP probe type requires stats export interval to be at least twice of the
    60  	// max(interval, timeout).
    61  	if p.GetType() == configpb.ProbeDef_UDP {
    62  		minIntv = 2 * minIntv
    63  	}
    64  
    65  	if minIntv < defaultStatsExtportIntv {
    66  		return defaultStatsExtportIntv
    67  	}
    68  	return minIntv
    69  }
    70  
    71  func ipv(v *configpb.ProbeDef_IPVersion) int {
    72  	if v == nil {
    73  		return 0
    74  	}
    75  
    76  	switch *v {
    77  	case configpb.ProbeDef_IPV4:
    78  		return 4
    79  	case configpb.ProbeDef_IPV6:
    80  		return 6
    81  	default:
    82  		return 0
    83  	}
    84  }
    85  
    86  // getSourceFromConfig returns the source IP from the config either directly
    87  // or by resolving the network interface to an IP, depending on which is provided.
    88  func getSourceIPFromConfig(p *configpb.ProbeDef, l *logger.Logger) (net.IP, error) {
    89  	switch p.SourceIpConfig.(type) {
    90  
    91  	case *configpb.ProbeDef_SourceIp:
    92  		sourceIP := net.ParseIP(p.GetSourceIp())
    93  		if sourceIP == nil {
    94  			return nil, fmt.Errorf("invalid source IP: %s", p.GetSourceIp())
    95  		}
    96  
    97  		// If ip_version is configured, make sure source_ip matches it.
    98  		if ipv(p.IpVersion) != 0 && iputils.IPVersion(sourceIP) != ipv(p.IpVersion) {
    99  			return nil, fmt.Errorf("configured source_ip (%s) doesn't match the ip_version (%d)", p.GetSourceIp(), ipv(p.IpVersion))
   100  		}
   101  
   102  		return sourceIP, nil
   103  
   104  	case *configpb.ProbeDef_SourceInterface:
   105  		return iputils.ResolveIntfAddr(p.GetSourceInterface(), ipv(p.IpVersion))
   106  
   107  	default:
   108  		return nil, fmt.Errorf("unknown source type: %v", p.GetSourceIpConfig())
   109  	}
   110  }
   111  
   112  // BuildProbeOptions builds probe's options using the provided config and some
   113  // global params.
   114  func BuildProbeOptions(p *configpb.ProbeDef, ldLister endpoint.Lister, globalTargetsOpts *targetspb.GlobalTargetsOptions, l *logger.Logger) (*Options, error) {
   115  	opts := &Options{
   116  		Interval:  time.Duration(p.GetIntervalMsec()) * time.Millisecond,
   117  		Timeout:   time.Duration(p.GetTimeoutMsec()) * time.Millisecond,
   118  		IPVersion: ipv(p.IpVersion),
   119  	}
   120  
   121  	var err error
   122  	if opts.Logger, err = logger.NewCloudproberLog(p.GetName()); err != nil {
   123  		return nil, fmt.Errorf("error in initializing logger for the probe (%s): %v", p.GetName(), err)
   124  	}
   125  
   126  	if opts.Targets, err = targets.New(p.GetTargets(), ldLister, globalTargetsOpts, l, opts.Logger); err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	if latencyDist := p.GetLatencyDistribution(); latencyDist != nil {
   131  		var d *metrics.Distribution
   132  		if d, err = metrics.NewDistributionFromProto(latencyDist); err != nil {
   133  			return nil, fmt.Errorf("error creating distribution from the specification (%v): %v", latencyDist, err)
   134  		}
   135  		opts.LatencyDist = d
   136  	}
   137  
   138  	// latency_unit is specified as a human-readable string, e.g. ns, ms, us etc.
   139  	if opts.LatencyUnit, err = time.ParseDuration("1" + p.GetLatencyUnit()); err != nil {
   140  		return nil, fmt.Errorf("failed to parse the latency unit (%s): %v", p.GetLatencyUnit(), err)
   141  	}
   142  
   143  	if len(p.GetValidator()) > 0 {
   144  		opts.Validators, err = validators.Init(p.GetValidator(), opts.Logger)
   145  		if err != nil {
   146  			return nil, fmt.Errorf("failed to initialize validators: %v", err)
   147  		}
   148  	}
   149  
   150  	if p.GetSourceIpConfig() != nil {
   151  		opts.SourceIP, err = getSourceIPFromConfig(p, l)
   152  		if err != nil {
   153  			return nil, fmt.Errorf("failed to get source address for the probe: %v", err)
   154  		}
   155  		// Set IPVersion from SourceIP if not already set.
   156  		if opts.IPVersion == 0 {
   157  			opts.IPVersion = iputils.IPVersion(opts.SourceIP)
   158  		}
   159  	}
   160  
   161  	if p.StatsExportIntervalMsec == nil {
   162  		opts.StatsExportInterval = defaultStatsExportInterval(p, opts)
   163  	} else {
   164  		opts.StatsExportInterval = time.Duration(p.GetStatsExportIntervalMsec()) * time.Millisecond
   165  		if opts.StatsExportInterval < opts.Interval {
   166  			return nil, fmt.Errorf("stats_export_interval (%d ms) smaller than probe interval %v", p.GetStatsExportIntervalMsec(), opts.Interval)
   167  		}
   168  	}
   169  
   170  	opts.AdditionalLabels = parseAdditionalLabels(p)
   171  
   172  	if !p.GetDebugOptions().GetLogMetrics() {
   173  		opts.LogMetrics = func(em *metrics.EventMetrics) {}
   174  	} else {
   175  		opts.LogMetrics = func(em *metrics.EventMetrics) {
   176  			if opts.Logger != nil {
   177  				opts.Logger.Info(em.String())
   178  			}
   179  		}
   180  	}
   181  
   182  	return opts, nil
   183  }
   184  
   185  // DefaultOptions returns default options, capturing default values for the
   186  // various fields.
   187  func DefaultOptions() *Options {
   188  	p := &configpb.ProbeDef{
   189  		Targets: &targetspb.TargetsDef{
   190  			Type: &targetspb.TargetsDef_DummyTargets{},
   191  		},
   192  	}
   193  
   194  	opts, err := BuildProbeOptions(p, nil, nil, nil)
   195  	// Without no user input, there should be no errors. We execute this as part
   196  	// of the tests.
   197  	if err != nil {
   198  		panic(err)
   199  	}
   200  
   201  	return opts
   202  }