github.com/letsencrypt/boulder@v0.20251208.0/observer/probers/crl/crl_conf.go (about)

     1  package probers
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  
     7  	"github.com/prometheus/client_golang/prometheus"
     8  
     9  	"github.com/letsencrypt/boulder/observer/probers"
    10  	"github.com/letsencrypt/boulder/strictyaml"
    11  )
    12  
    13  const (
    14  	nextUpdateName = "obs_crl_next_update"
    15  	thisUpdateName = "obs_crl_this_update"
    16  	certCountName  = "obs_crl_revoked_cert_count"
    17  )
    18  
    19  // CRLConf is exported to receive YAML configuration
    20  type CRLConf struct {
    21  	URL         string `yaml:"url"`
    22  	Partitioned bool   `yaml:"partitioned"`
    23  }
    24  
    25  // Kind returns a name that uniquely identifies the `Kind` of `Configurer`.
    26  func (c CRLConf) Kind() string {
    27  	return "CRL"
    28  }
    29  
    30  // UnmarshalSettings constructs a CRLConf object from YAML as bytes.
    31  func (c CRLConf) UnmarshalSettings(settings []byte) (probers.Configurer, error) {
    32  	var conf CRLConf
    33  	err := strictyaml.Unmarshal(settings, &conf)
    34  
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return conf, nil
    39  }
    40  
    41  func (c CRLConf) validateURL() error {
    42  	url, err := url.Parse(c.URL)
    43  	if err != nil {
    44  		return fmt.Errorf(
    45  			"invalid 'url', got: %q, expected a valid url", c.URL)
    46  	}
    47  	if url.Scheme == "" {
    48  		return fmt.Errorf(
    49  			"invalid 'url', got: %q, missing scheme", c.URL)
    50  	}
    51  	return nil
    52  }
    53  
    54  // MakeProber constructs a `CRLProbe` object from the contents of the
    55  // bound `CRLConf` object. If the `CRLConf` cannot be validated, an
    56  // error appropriate for end-user consumption is returned instead.
    57  func (c CRLConf) MakeProber(collectors map[string]prometheus.Collector) (probers.Prober, error) { // validate `url` err := c.validateURL()
    58  	// validate `url`
    59  	err := c.validateURL()
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	// validate the prometheus collectors that were passed in
    65  	coll, ok := collectors[nextUpdateName]
    66  	if !ok {
    67  		return nil, fmt.Errorf("crl prober did not receive collector %q", nextUpdateName)
    68  	}
    69  	nextUpdateColl, ok := coll.(*prometheus.GaugeVec)
    70  	if !ok {
    71  		return nil, fmt.Errorf("crl prober received collector %q of wrong type, got: %T, expected *prometheus.GaugeVec", nextUpdateName, coll)
    72  	}
    73  
    74  	coll, ok = collectors[thisUpdateName]
    75  	if !ok {
    76  		return nil, fmt.Errorf("crl prober did not receive collector %q", thisUpdateName)
    77  	}
    78  	thisUpdateColl, ok := coll.(*prometheus.GaugeVec)
    79  	if !ok {
    80  		return nil, fmt.Errorf("crl prober received collector %q of wrong type, got: %T, expected *prometheus.GaugeVec", thisUpdateName, coll)
    81  	}
    82  
    83  	coll, ok = collectors[certCountName]
    84  	if !ok {
    85  		return nil, fmt.Errorf("crl prober did not receive collector %q", certCountName)
    86  	}
    87  	certCountColl, ok := coll.(*prometheus.GaugeVec)
    88  	if !ok {
    89  		return nil, fmt.Errorf("crl prober received collector %q of wrong type, got: %T, expected *prometheus.GaugeVec", certCountName, coll)
    90  	}
    91  
    92  	return CRLProbe{c.URL, c.Partitioned, nextUpdateColl, thisUpdateColl, certCountColl}, nil
    93  }
    94  
    95  // Instrument constructs any `prometheus.Collector` objects the `CRLProbe` will
    96  // need to report its own metrics. A map is returned containing the constructed
    97  // objects, indexed by the name of the prometheus metric. If no objects were
    98  // constructed, nil is returned.
    99  func (c CRLConf) Instrument() map[string]prometheus.Collector {
   100  	nextUpdate := prometheus.Collector(prometheus.NewGaugeVec(
   101  		prometheus.GaugeOpts{
   102  			Name: nextUpdateName,
   103  			Help: "CRL nextUpdate Unix timestamp in seconds",
   104  		}, []string{"url"},
   105  	))
   106  	thisUpdate := prometheus.Collector(prometheus.NewGaugeVec(
   107  		prometheus.GaugeOpts{
   108  			Name: thisUpdateName,
   109  			Help: "CRL thisUpdate Unix timestamp in seconds",
   110  		}, []string{"url"},
   111  	))
   112  	certCount := prometheus.Collector(prometheus.NewGaugeVec(
   113  		prometheus.GaugeOpts{
   114  			Name: certCountName,
   115  			Help: "number of certificates revoked in CRL",
   116  		}, []string{"url"},
   117  	))
   118  	return map[string]prometheus.Collector{
   119  		nextUpdateName: nextUpdate,
   120  		thisUpdateName: thisUpdate,
   121  		certCountName:  certCount,
   122  	}
   123  }
   124  
   125  // init is called at runtime and registers `CRLConf`, a `Prober`
   126  // `Configurer` type, as "CRL".
   127  func init() {
   128  	probers.Register(CRLConf{})
   129  }