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 }