github.com/argoproj/argo-cd/v3@v3.2.1/reposerver/gpgwatcher.go (about) 1 package reposerver 2 3 import ( 4 "errors" 5 "fmt" 6 "path" 7 "time" 8 9 "github.com/fsnotify/fsnotify" 10 log "github.com/sirupsen/logrus" 11 12 "github.com/argoproj/argo-cd/v3/util/gpg" 13 ) 14 15 const maxRecreateRetries = 5 16 17 // StartGPGWatcher watches a given directory for creation and deletion of files and syncs the GPG keyring 18 func StartGPGWatcher(sourcePath string) error { 19 log.Infof("Starting GPG sync watcher on directory '%s'", sourcePath) 20 forceSync := false 21 watcher, err := fsnotify.NewWatcher() 22 if err != nil { 23 return fmt.Errorf("failed to create fsnotify Watcher: %w", err) 24 } 25 defer func(watcher *fsnotify.Watcher) { 26 if err = watcher.Close(); err != nil { 27 log.Errorf("Error closing watcher: %v", err) 28 } 29 }(watcher) 30 31 done := make(chan bool) 32 go func() { 33 for { 34 select { 35 case event, ok := <-watcher.Events: 36 if !ok { 37 return 38 } 39 if event.Has(fsnotify.Create) || event.Has(fsnotify.Remove) { 40 // In case our watched path is re-created (i.e. during e2e tests), we need to watch again 41 // For more robustness, we retry re-creating the watcher up to maxRecreateRetries 42 if event.Name == sourcePath && event.Has(fsnotify.Remove) { 43 log.Warnf("Re-creating watcher on %s", sourcePath) 44 attempt := 0 45 for { 46 err = watcher.Add(sourcePath) 47 if err != nil { 48 log.Errorf("Error re-creating watcher on %s: %v", sourcePath, err) 49 if attempt < maxRecreateRetries { 50 attempt++ 51 log.Infof("Retrying to re-create watcher, attempt %d of %d", attempt, maxRecreateRetries) 52 time.Sleep(1 * time.Second) 53 continue 54 } 55 log.Errorf("Maximum retries exceeded.") 56 close(done) 57 return 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 fmt.Errorf("failed to add a new source to the watcher: %w", err) 87 } 88 <-done 89 return errors.New("abnormal termination of GPG watcher, refusing to continue") 90 }