1414package main
1515
1616import (
17- "errors"
1817 "fmt"
1918 "log/slog"
20- "net"
2119 "net/http"
22- "net/http/pprof"
23- "net/url"
2420 "os"
2521 "os/signal"
2622 "path"
@@ -235,37 +231,6 @@ func main() {
235231 return
236232 }
237233
238- // Infer or set snmp exporter externalURL
239- listenAddrs := toolkitFlags .WebListenAddresses
240- if * externalURL == "" && * toolkitFlags .WebSystemdSocket {
241- logger .Error ("Cannot automatically infer external URL with systemd socket listener. Please provide --web.external-url" )
242- os .Exit (1 )
243- } else if * externalURL == "" && len (* listenAddrs ) > 1 {
244- logger .Info ("Inferring external URL from first provided listen address" )
245- }
246-
247- beURL , err := computeExternalURL (* externalURL , (* listenAddrs )[0 ])
248- if err != nil {
249- logger .Error ("Failed to determine external URL" , "err" , err )
250- os .Exit (1 )
251- }
252- logger .Debug ("External URL" , "url" , beURL .String ())
253-
254- // Default -web.route-prefix to path of -web.external-url
255- if * routePrefix == "" {
256- * routePrefix = beURL .Path
257- }
258-
259- // routePrefix must always be at least '/'
260- * routePrefix = "/" + strings .Trim (* routePrefix , "/" )
261- logger .Debug ("Route prefix" , "prefix" , * routePrefix )
262- // routePrefix requires path to have trailing "/" in order
263- // for browsers to interpret the path-relative path correctly, instead of stripping it.
264- if * routePrefix != "/" {
265- * routePrefix = * routePrefix + "/"
266- }
267- logger .Debug (* routePrefix )
268-
269234 hup := make (chan os.Signal , 1 )
270235 reloadCh = make (chan chan error )
271236 signal .Notify (hup , syscall .SIGHUP )
@@ -331,35 +296,16 @@ func main() {
331296 ),
332297 }
333298
334- // Match Prometheus behavior and redirect over externalURL for root path only
335- // if routePrefix is different from "/"
336- if * routePrefix != "/" {
337- http .HandleFunc ("/" , func (w http.ResponseWriter , r * http.Request ) {
338- if r .URL .Path != "/" {
339- http .NotFound (w , r )
340- return
341- }
342- http .Redirect (w , r , beURL .String (), http .StatusFound )
343- })
344- }
345-
346- http .Handle (path .Join (* routePrefix , * metricsPath ), promhttp .Handler ()) // Normal metrics endpoint for SNMP exporter itself.
347- // Endpoint to do SNMP scrapes.
348- http .HandleFunc (path .Join (* routePrefix , proberPath ), func (w http.ResponseWriter , r * http.Request ) {
349- handler (w , r , logger , exporterMetrics )
350- })
351- http .HandleFunc (path .Join (* routePrefix , "/-/reload" ), updateConfiguration ) // Endpoint to reload configuration.
352- // Serve pprof under the route prefix. These links are displayed on the landing page.
353- http .HandleFunc (path .Join (* routePrefix , "debug/pprof/" ), pprof .Index )
354- http .HandleFunc (path .Join (* routePrefix , "debug/pprof/profile" ), pprof .Profile )
355- http .HandleFunc (path .Join (* routePrefix , "debug/pprof/heap" ), pprof .Handler ("heap" ).ServeHTTP )
356-
357299 if * metricsPath != "/" && * metricsPath != "" {
358300 landingConfig := web.LandingConfig {
359- Name : "SNMP Exporter" ,
360- Description : "Prometheus Exporter for SNMP targets" ,
361- Version : version .Info (),
362- RoutePrefix : * routePrefix ,
301+ Name : "SNMP Exporter" ,
302+ Description : "Prometheus Exporter for SNMP targets" ,
303+ Version : version .Info (),
304+ RoutePrefix : * routePrefix ,
305+ ExternalURL : * externalURL ,
306+ ListenAddresses : * toolkitFlags .WebListenAddresses ,
307+ UseSystemdSocket : * toolkitFlags .WebSystemdSocket ,
308+ Logger : logger ,
363309 Form : web.LandingForm {
364310 Action : proberPath ,
365311 Inputs : []web.LandingFormInput {
@@ -397,14 +343,24 @@ func main() {
397343 },
398344 },
399345 }
400- landingPage , err := web .NewLandingPage (landingConfig )
346+ landingPage , processedRoutePrefix , err := web .NewLandingPage (landingConfig )
401347 if err != nil {
402348 logger .Error ("Error creating landing page" , "err" , err )
403349 os .Exit (1 )
404350 }
351+ * routePrefix = processedRoutePrefix
405352 http .Handle (* routePrefix , landingPage )
406353 }
407354
355+ http .Handle (path .Join (* routePrefix , * metricsPath ), promhttp .Handler ()) // Normal metrics endpoint for SNMP exporter itself.
356+
357+ // Endpoint to do SNMP scrapes.
358+ http .HandleFunc (path .Join (* routePrefix , proberPath ), func (w http.ResponseWriter , r * http.Request ) {
359+ handler (w , r , logger , exporterMetrics )
360+ })
361+
362+ http .HandleFunc (path .Join (* routePrefix , "/-/reload" ), updateConfiguration ) // Endpoint to reload configuration.
363+
408364 http .HandleFunc (path .Join (* routePrefix , configPath ), func (w http.ResponseWriter , r * http.Request ) {
409365 sc .RLock ()
410366 c , err := yaml .Marshal (sc .C )
@@ -423,41 +379,3 @@ func main() {
423379 os .Exit (1 )
424380 }
425381}
426-
427- func startsOrEndsWithQuote (s string ) bool {
428- return strings .HasPrefix (s , "\" " ) || strings .HasPrefix (s , "'" ) ||
429- strings .HasSuffix (s , "\" " ) || strings .HasSuffix (s , "'" )
430- }
431-
432- // computeExternalURL computes a sanitized external URL from a raw input. It infers unset
433- // URL parts from the OS and the given listen address.
434- func computeExternalURL (u , listenAddr string ) (* url.URL , error ) {
435- if u == "" {
436- hostname , err := os .Hostname ()
437- if err != nil {
438- return nil , err
439- }
440- _ , port , err := net .SplitHostPort (listenAddr )
441- if err != nil {
442- return nil , err
443- }
444- u = fmt .Sprintf ("http://%s:%s/" , hostname , port )
445- }
446-
447- if startsOrEndsWithQuote (u ) {
448- return nil , errors .New ("URL must not begin or end with quotes" )
449- }
450-
451- eu , err := url .Parse (u )
452- if err != nil {
453- return nil , err
454- }
455-
456- ppref := strings .TrimRight (eu .Path , "/" )
457- if ppref != "" && ! strings .HasPrefix (ppref , "/" ) {
458- ppref = "/" + ppref
459- }
460- eu .Path = ppref
461-
462- return eu , nil
463- }
0 commit comments