github.com/argoproj/argo-cd/v2@v2.10.9/reposerver/gpgwatcher.go (about)

     1  package reposerver
     2  
     3  import (
     4  	"fmt"
     5  	"path"
     6  	"time"
     7  
     8  	"github.com/fsnotify/fsnotify"
     9  	log "github.com/sirupsen/logrus"
    10  
    11  	"github.com/argoproj/argo-cd/v2/util/gpg"
    12  )
    13  
    14  const maxRecreateRetries = 5
    15  
    16  // StartGPGWatcher watches a given directory for creation and deletion of files and syncs the GPG keyring
    17  func StartGPGWatcher(sourcePath string) error {
    18  	log.Infof("Starting GPG sync watcher on directory '%s'", sourcePath)
    19  	forceSync := false
    20  	watcher, err := fsnotify.NewWatcher()
    21  	if err != nil {
    22  		return err
    23  	}
    24  	defer func(watcher *fsnotify.Watcher) {
    25  		if err = watcher.Close(); err != nil {
    26  			log.Errorf("Error closing watcher: %v", err)
    27  		}
    28  	}(watcher)
    29  
    30  	done := make(chan bool)
    31  	go func() {
    32  		for {
    33  			select {
    34  			case event, ok := <-watcher.Events:
    35  				if !ok {
    36  					return
    37  				}
    38  				if event.Has(fsnotify.Create) || event.Has(fsnotify.Remove) {
    39  					// In case our watched path is re-created (i.e. during e2e tests), we need to watch again
    40  					// For more robustness, we retry re-creating the watcher up to maxRecreateRetries
    41  					if event.Name == sourcePath && event.Has(fsnotify.Remove) {
    42  						log.Warnf("Re-creating watcher on %s", sourcePath)
    43  						attempt := 0
    44  						for {
    45  							err = watcher.Add(sourcePath)
    46  							if err != nil {
    47  								log.Errorf("Error re-creating watcher on %s: %v", sourcePath, err)
    48  								if attempt < maxRecreateRetries {
    49  									attempt += 1
    50  									log.Infof("Retrying to re-create watcher, attempt %d of %d", attempt, maxRecreateRetries)
    51  									time.Sleep(1 * time.Second)
    52  									continue
    53  								} else {
    54  									log.Errorf("Maximum retries exceeded.")
    55  									close(done)
    56  									return
    57  								}
    58  							}
    59  							break
    60  						}
    61  						// Force sync because we probably missed an event
    62  						forceSync = true
    63  					}
    64  					if gpg.IsShortKeyID(path.Base(event.Name)) || forceSync {
    65  						log.Infof("Updating GPG keyring on filesystem event")
    66  						added, removed, err := gpg.SyncKeyRingFromDirectory(sourcePath)
    67  						if err != nil {
    68  							log.Errorf("Could not sync keyring: %s", err.Error())
    69  						} else {
    70  							log.Infof("Result of sync operation: keys added: %d, keys removed: %d", len(added), len(removed))
    71  						}
    72  						forceSync = false
    73  					}
    74  				}
    75  			case err, ok := <-watcher.Errors:
    76  				if !ok {
    77  					return
    78  				}
    79  				log.Errorf("%v", err)
    80  			}
    81  		}
    82  	}()
    83  
    84  	err = watcher.Add(sourcePath)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	<-done
    89  	return fmt.Errorf("Abnormal termination of GPG watcher, refusing to continue.")
    90  }