diff --git a/storageops/reconcile-util.go b/storageops/reconcile-util.go index 17bfc36..ce8af66 100644 --- a/storageops/reconcile-util.go +++ b/storageops/reconcile-util.go @@ -98,6 +98,32 @@ func DoesCertificateSatisfy(c *storage.Certificate, t *storage.Target) bool { return true } +func FindBestCertificateSatisfyingFromCache(certArray []*storage.Certificate, t *storage.Target) (*storage.Certificate, error) { + var bestCert *storage.Certificate + + for _, c := range certArray { + if DoesCertificateSatisfy(c, t) { + isBetterThan, err := CertificateBetterThan(c, bestCert) + if err != nil { + continue + } + + if isBetterThan { + log.Tracef("findBestCertificateSatisfying: %v > %v", c, bestCert) + bestCert = c + } else { + log.Tracef("findBestCertificateSatisfying: %v <= %v", c, bestCert) + } + } + } + + if bestCert == nil { + return nil, fmt.Errorf("%v: no certificate satisfies this target", t) + } + + return bestCert, nil +} + func FindBestCertificateSatisfying(s storage.Store, t *storage.Target) (*storage.Certificate, error) { var bestCert *storage.Certificate diff --git a/storageops/reconcile.go b/storageops/reconcile.go index 5165d78..3cf6167 100644 --- a/storageops/reconcile.go +++ b/storageops/reconcile.go @@ -33,6 +33,8 @@ var InternalClock = clock.Default() // Internal use only. Used for testing purposes. Do not change. var InternalHTTPClient *http.Client +var reconcileMap = make(map[string][]*storage.Certificate) + // Optional configuration for the Reconcile operation. type ReconcileConfig struct { // If non-empty, a set of target names/paths to limit reconciliation to. @@ -138,9 +140,10 @@ func (r *reconcile) Relink() error { } var updatedHostnames []string + r.ensureMap() for name, tgt := range hostnameTargetMapping { - c, err := FindBestCertificateSatisfying(r.store, tgt) + c, err := FindBestCertificateSatisfyingFromCache(reconcileMap[tgt.Satisfy.Names[0]], tgt) if err != nil { log.Debugf("could not find certificate satisfying %v: %v", tgt, err) continue @@ -398,16 +401,33 @@ func (r *reconcile) targetIsSelected(t *storage.Target) (selected bool, err erro return } +func (r *reconcile) ensureMap() error { + r.store.VisitCertificates(func(c *storage.Certificate) error { + cc, err := x509.ParseCertificate(c.Certificates[0]) + if err != nil { + log.Debugf("%v cannot parse: %v", c, err) + return err + } + + for _, name := range cc.DNSNames { + reconcileMap[name] = append(reconcileMap[name], c) + } + return nil + }) + return nil +} + func (r *reconcile) processTargets() error { var merr util.MultiError + r.ensureMap() + r.store.VisitTargets(func(t *storage.Target) error { selected, err := r.targetIsSelected(t) if err != nil || !selected { return err } - - c, err := FindBestCertificateSatisfying(r.store, t) + c, err := FindBestCertificateSatisfyingFromCache(reconcileMap[t.Satisfy.Names[0]], t) log.Debugf("%v: best certificate satisfying is %v, err=%v", t, c, err) if err == nil && !CertificateNeedsRenewing(c, t) { log.Debugf("%v: have best certificate which does not need renewing, skipping target", t) @@ -705,6 +725,17 @@ func (r *reconcile) downloadCertificateAdaptive(c *storage.Certificate) error { return err } + // Add it to the reconcile map + cc, err := x509.ParseCertificate(c.Certificates[0]) + if err != nil { + log.Debugf("%v cannot parse: %v", c, err) + return err + } + + for _, name := range cc.DNSNames { + reconcileMap[name] = append(reconcileMap[name], c) + } + return nil }