11package git
22
33import (
4+ "context"
45 "fmt"
56 "os"
67 "os/exec"
@@ -17,6 +18,7 @@ import (
1718 "k8s.io/apimachinery/pkg/runtime"
1819 "k8s.io/apimachinery/pkg/runtime/schema"
1920 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
21+ "k8s.io/apimachinery/pkg/util/wait"
2022 "k8s.io/client-go/tools/cache"
2123 "k8s.io/klog/v2"
2224 "sigs.k8s.io/yaml"
@@ -56,12 +58,12 @@ func NewGitStorage(path string) (*GitStorage, error) {
5658 return storage , nil
5759}
5860
59- func (s * GitStorage ) GC () error {
60- return s .execGit ("gc" )
61+ func (s * GitStorage ) GC (ctx context. Context ) error {
62+ return s .execGit (ctx , "gc" )
6163}
6264
6365// handle handles different operations on git
64- func (s * GitStorage ) handle (timestamp time.Time , gvr schema.GroupVersionResource , oldObj , obj * unstructured.Unstructured , delete bool ) {
66+ func (s * GitStorage ) handle (ctx context. Context , timestamp time.Time , gvr schema.GroupVersionResource , oldObj , obj * unstructured.Unstructured , delete bool ) {
6567 filePath , content , err := decodeUnstructuredObject (gvr , obj )
6668 if err != nil {
6769 klog .Warningf ("Decoding %q failed: %v" , filePath , err )
@@ -89,14 +91,14 @@ func (s *GitStorage) handle(timestamp time.Time, gvr schema.GroupVersionResource
8991 // Add it first before removing it.
9092 if os .IsNotExist (err ) {
9193 klog .Info ("Observed delete of file we haven't previously observed. Adding it first." )
92- s .handle (timestamp , gvr , nil , obj , false )
93- s .handle (timestamp , gvr , nil , obj , true )
94+ s .handle (ctx , timestamp , gvr , nil , obj , false )
95+ s .handle (ctx , timestamp , gvr , nil , obj , true )
9496 return
9597 } else {
9698 klog .Errorf ("Error removing %q: %v" , filePath , err )
9799 }
98100 }
99- if err := s .commitRemove (timestamp , filePath , "unknown" , ocCommand ); err != nil {
101+ if err := s .commitRemove (ctx , timestamp , filePath , "unknown" , ocCommand ); err != nil {
100102 klog .Error (err )
101103 }
102104
@@ -119,33 +121,33 @@ func (s *GitStorage) handle(timestamp time.Time, gvr schema.GroupVersionResource
119121 switch operation {
120122 case gitOpAdded :
121123 klog .Infof ("Calling commitAdd for %s" , filePath )
122- if err := s .commitAdd (timestamp , filePath , modifyingUser , ocCommand ); err != nil {
124+ if err := s .commitAdd (ctx , timestamp , filePath , modifyingUser , ocCommand ); err != nil {
123125 klog .Error (err )
124126 }
125127 case gitOpModified :
126128 klog .Infof ("Calling commitModify for %s" , filePath )
127- if err := s .commitModify (timestamp , filePath , modifyingUser , ocCommand ); err != nil {
129+ if err := s .commitModify (ctx , timestamp , filePath , modifyingUser , ocCommand ); err != nil {
128130 klog .Error (err )
129131 }
130132 default :
131133 klog .Errorf ("unhandled case for %s: %d" , filePath , operation )
132134 }
133135}
134136
135- func (s * GitStorage ) OnAdd (timestamp time.Time , gvr schema.GroupVersionResource , obj interface {}) {
137+ func (s * GitStorage ) OnAdd (ctx context. Context , timestamp time.Time , gvr schema.GroupVersionResource , obj interface {}) {
136138 objUnstructured := obj .(* unstructured.Unstructured )
137139
138- s .handle (timestamp , gvr , nil , objUnstructured , false )
140+ s .handle (ctx , timestamp , gvr , nil , objUnstructured , false )
139141}
140142
141- func (s * GitStorage ) OnUpdate (timestamp time.Time , gvr schema.GroupVersionResource , oldObj , obj interface {}) {
143+ func (s * GitStorage ) OnUpdate (ctx context. Context , timestamp time.Time , gvr schema.GroupVersionResource , oldObj , obj interface {}) {
142144 objUnstructured := obj .(* unstructured.Unstructured )
143145 oldObjUnstructured := oldObj .(* unstructured.Unstructured )
144146
145- s .handle (timestamp , gvr , oldObjUnstructured , objUnstructured , false )
147+ s .handle (ctx , timestamp , gvr , oldObjUnstructured , objUnstructured , false )
146148}
147149
148- func (s * GitStorage ) OnDelete (timestamp time.Time , gvr schema.GroupVersionResource , obj interface {}) {
150+ func (s * GitStorage ) OnDelete (ctx context. Context , timestamp time.Time , gvr schema.GroupVersionResource , obj interface {}) {
149151 objUnstructured , ok := obj .(* unstructured.Unstructured )
150152 if ! ok {
151153 tombstone , ok := obj .(cache.DeletedFinalStateUnknown )
@@ -160,7 +162,7 @@ func (s *GitStorage) OnDelete(timestamp time.Time, gvr schema.GroupVersionResour
160162 }
161163 }
162164
163- s .handle (timestamp , gvr , nil , objUnstructured , true )
165+ s .handle (ctx , timestamp , gvr , nil , objUnstructured , true )
164166}
165167
166168// guessAtModifyingUsers tries to figure out who modified the resource
@@ -223,62 +225,69 @@ func resourceFilename(gvr schema.GroupVersionResource, namespace, name string) s
223225 return filepath .Join ("namespaces" , namespace , groupStr , gvr .Resource , name + ".yaml" )
224226}
225227
226- func (s * GitStorage ) execGit (args ... string ) error {
228+ func (s * GitStorage ) execGit (ctx context. Context , args ... string ) error {
227229 // Disable automatic garbage collection to avoid racing with other processes.
228230 args = append ([]string {"-c" , "gc.auto=0" }, args ... )
229231
230- osCommand := exec .Command ("git" , args ... )
231- osCommand .Dir = s .path
232- output , err := osCommand .CombinedOutput ()
233- if err != nil {
234- klog .Errorf ("Ran git %v\n %v\n \n " , args , string (output ))
235- return err
236- }
237- return nil
232+ // The git store should no longer race with itself since we
233+ // disabled auto gc so this should never happen in a CI run. However,
234+ // manually executed git commands may still cause errors, so we have a retry
235+ // loop for robustness.
236+ return wait .PollUntilContextCancel (ctx , 1 * time .Second , true , func (ctx context.Context ) (bool , error ) {
237+ osCommand := exec .Command ("git" , args ... )
238+ osCommand .Dir = s .path
239+ output , err := osCommand .CombinedOutput ()
240+ if err != nil {
241+ klog .Errorf ("Ran git %v\n %v\n \n " , args , string (output ))
242+ // Don't return the error or we'll stop polling.
243+ return false , nil
244+ }
245+ return true , nil
246+ })
238247}
239248
240- func (s * GitStorage ) commit (timestamp time.Time , path , author , commitMessage string ) error {
249+ func (s * GitStorage ) commit (ctx context. Context , timestamp time.Time , path , author , commitMessage string ) error {
241250 authorString := fmt .
Sprintf (
"%s <[email protected] >" ,
author )
242251 dateString := timestamp .Format (time .RFC3339 )
243252
244- return s .execGit ("commit" , "--author" , authorString , "--date" , dateString , "-m" , commitMessage )
253+ return s .execGit (ctx , "commit" , "--author" , authorString , "--date" , dateString , "-m" , commitMessage )
245254}
246255
247- func (s * GitStorage ) commitAdd (timestamp time.Time , path , author , ocCommand string ) error {
248- if err := s .execGit ("add" , path ); err != nil {
256+ func (s * GitStorage ) commitAdd (ctx context. Context , timestamp time.Time , path , author , ocCommand string ) error {
257+ if err := s .execGit (ctx , "add" , path ); err != nil {
249258 return err
250259 }
251260
252261 commitMessage := fmt .Sprintf ("added %s" , ocCommand )
253- if err := s .commit (timestamp , path , author , commitMessage ); err != nil {
262+ if err := s .commit (ctx , timestamp , path , author , commitMessage ); err != nil {
254263 return err
255264 }
256265
257266 klog .Infof ("Add: %v -- %v added %v" , path , author , ocCommand )
258267 return nil
259268}
260269
261- func (s * GitStorage ) commitModify (timestamp time.Time , path , author , ocCommand string ) error {
262- if err := s .execGit ("add" , path ); err != nil {
270+ func (s * GitStorage ) commitModify (ctx context. Context , timestamp time.Time , path , author , ocCommand string ) error {
271+ if err := s .execGit (ctx , "add" , path ); err != nil {
263272 return err
264273 }
265274
266275 commitMessage := fmt .Sprintf ("modifed %s" , ocCommand )
267- if err := s .commit (timestamp , path , author , commitMessage ); err != nil {
276+ if err := s .commit (ctx , timestamp , path , author , commitMessage ); err != nil {
268277 return err
269278 }
270279
271280 klog .Infof ("Modified: %v -- %v updated %v" , path , author , ocCommand )
272281 return nil
273282}
274283
275- func (s * GitStorage ) commitRemove (timestamp time.Time , path , author , ocCommand string ) error {
276- if err := s .execGit ("rm" , path ); err != nil {
284+ func (s * GitStorage ) commitRemove (ctx context. Context , timestamp time.Time , path , author , ocCommand string ) error {
285+ if err := s .execGit (ctx , "rm" , path ); err != nil {
277286 return err
278287 }
279288
280289 commitMessage := fmt .Sprintf ("removed %s" , ocCommand )
281- if err := s .commit (timestamp , path , author , commitMessage ); err != nil {
290+ if err := s .commit (ctx , timestamp , path , author , commitMessage ); err != nil {
282291 return err
283292 }
284293
0 commit comments