-
Notifications
You must be signed in to change notification settings - Fork 420
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
506 additions
and
231 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package fileutil | ||
|
||
import ( | ||
"os" | ||
"time" | ||
|
||
"github.com/fsnotify/fsnotify" | ||
"github.com/sirupsen/logrus" | ||
"k8s.io/apimachinery/pkg/util/wait" | ||
"sigs.k8s.io/aws-iam-authenticator/pkg/metrics" | ||
) | ||
|
||
type FileChangeCallBack interface { | ||
CallBackForFileLoad(dynamicContent []byte) error | ||
CallBackForFileDeletion() error | ||
} | ||
|
||
func waitUntilFileAvailable(filename string, stopCh <-chan struct{}) { | ||
if _, err := os.Stat(filename); err == nil { | ||
return | ||
} | ||
ticker := time.NewTicker(1 * time.Second) | ||
defer ticker.Stop() | ||
for { | ||
select { | ||
case <-stopCh: | ||
logrus.Infof("startLoadDynamicFile: waitUntilFileAvailable exit because get stopCh, filename is %s", filename) | ||
return | ||
case <-ticker.C: | ||
if _, err := os.Stat(filename); err == nil { | ||
return | ||
} | ||
} | ||
} | ||
} | ||
|
||
func loadDynamicFile(filename string, stopCh <-chan struct{}) ([]byte, error) { | ||
waitUntilFileAvailable(filename, stopCh) | ||
if content, err := os.ReadFile(filename); err == nil { | ||
logrus.Infof("LoadDynamicFile: %v is available. content is %s", filename, string(content)) | ||
return content, nil | ||
} else { | ||
return nil, err | ||
} | ||
} | ||
|
||
func StartLoadDynamicFile(filename string, callBack FileChangeCallBack, stopCh <-chan struct{}) { | ||
go wait.Until(func() { | ||
// start to watch the file change | ||
watcher, err := fsnotify.NewWatcher() | ||
if err != nil { | ||
logrus.Errorf("startLoadDynamicFile: failed when call fsnotify.NewWatcher, %+v", err) | ||
metrics.Get().DynamicFileFailures.Inc() | ||
return | ||
} | ||
defer watcher.Close() | ||
content, err := loadDynamicFile(filename, stopCh) | ||
if err != nil { | ||
logrus.Errorf("StartLoadDynamicFile: error in loadDynamicFile, %v", err) | ||
return | ||
} | ||
err = watcher.Add(filename) | ||
if err != nil { | ||
logrus.Errorf("startLoadDynamicFile: could not add file to watcher %v", err) | ||
metrics.Get().DynamicFileFailures.Inc() | ||
return | ||
} | ||
if err := callBack.CallBackForFileLoad(content); err != nil { | ||
logrus.Errorf("StartLoadDynamicFile: error in callBackForFileLoad, %v", err) | ||
} | ||
for { | ||
select { | ||
case <-stopCh: | ||
logrus.Infof("startLoadDynamicFile: watching exit because stopCh closed, filename is %s", filename) | ||
return | ||
case event := <-watcher.Events: | ||
switch { | ||
case event.Op&fsnotify.Write == fsnotify.Write, event.Op&fsnotify.Create == fsnotify.Create: | ||
// reload the access entry file | ||
logrus.Info("startLoadDynamicFile: got WRITE/CREATE event reload it the memory") | ||
content, err := loadDynamicFile(filename, stopCh) | ||
if err != nil { | ||
logrus.Errorf("StartLoadDynamicFile: error in loadDynamicFile, %v", err) | ||
return | ||
} | ||
if err := callBack.CallBackForFileLoad(content); err != nil { | ||
logrus.Errorf("StartLoadDynamicFile: error in callBackForFileLoad, %v", err) | ||
} | ||
case event.Op&fsnotify.Rename == fsnotify.Rename, event.Op&fsnotify.Remove == fsnotify.Remove: | ||
logrus.Info("startLoadDynamicFile: got RENAME/REMOVE event") | ||
// test if the "REMOVE" is triggered by vi or cp cmd | ||
_, err := os.Stat(filename) | ||
if os.IsNotExist(err) { | ||
if err := callBack.CallBackForFileDeletion(); err != nil { | ||
logrus.Errorf("StartLoadDynamicFile: error in callBackForFileDeletion, %v", err) | ||
} | ||
} | ||
return | ||
} | ||
case err := <-watcher.Errors: | ||
logrus.Errorf("startLoadDynamicFile: watcher.Errors for dynamic file %v", err) | ||
metrics.Get().DynamicFileFailures.Inc() | ||
return | ||
} | ||
} | ||
}, time.Second, stopCh) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package fileutil | ||
|
||
import ( | ||
"os" | ||
"sync" | ||
"testing" | ||
"time" | ||
) | ||
|
||
var origFileContent = ` | ||
Abbatxt7095 | ||
` | ||
|
||
var updatedFileContent = ` | ||
efgwht2033 | ||
` | ||
|
||
type testStruct struct { | ||
content string | ||
expectedContent string | ||
mutex sync.Mutex | ||
} | ||
|
||
func (a *testStruct) CallBackForFileLoad(dynamicContent []byte) error { | ||
a.mutex.Lock() | ||
a.expectedContent = string(dynamicContent) | ||
defer a.mutex.Unlock() | ||
return nil | ||
} | ||
|
||
func (a *testStruct) CallBackForFileDeletion() error { | ||
a.mutex.Lock() | ||
a.expectedContent = "" | ||
defer a.mutex.Unlock() | ||
return nil | ||
} | ||
|
||
func TestLoadDynamicFile(t *testing.T) { | ||
cases := []struct { | ||
input string | ||
want string | ||
}{ | ||
{ | ||
"abcde", | ||
"abcde", | ||
}, | ||
{ | ||
"fghijk", | ||
"fghijk", | ||
}, | ||
{ | ||
"xyzopq", | ||
"xyzopq", | ||
}, | ||
{ | ||
"eks:test", | ||
"eks:test", | ||
}, | ||
} | ||
stopCh := make(chan struct{}) | ||
testA := &testStruct{} | ||
StartLoadDynamicFile("/tmp/util_test.txt", testA, stopCh) | ||
defer close(stopCh) | ||
time.Sleep(2 * time.Second) | ||
os.WriteFile("/tmp/util_test.txt", []byte("test"), 0777) | ||
for _, c := range cases { | ||
updateFile(testA, c.input, t) | ||
testA.mutex.Lock() | ||
if testA.expectedContent != c.want { | ||
t.Errorf( | ||
"Unexpected result: TestLoadDynamicFile: got: %s, wanted %s", | ||
testA.expectedContent, | ||
c.want, | ||
) | ||
} | ||
testA.mutex.Unlock() | ||
} | ||
} | ||
|
||
func updateFile(testA *testStruct, origFileContent string, t *testing.T) { | ||
testA.content = origFileContent | ||
data := []byte(origFileContent) | ||
err := os.WriteFile("/tmp/util_test.txt", data, 0600) | ||
if err != nil { | ||
t.Errorf("failed to create a local file /tmp/util_test.txt") | ||
} | ||
time.Sleep(1 * time.Second) | ||
} | ||
|
||
func TestDeleteDynamicFile(t *testing.T) { | ||
stopCh := make(chan struct{}) | ||
testA := &testStruct{} | ||
StartLoadDynamicFile("/tmp/delete.txt", testA, stopCh) | ||
defer close(stopCh) | ||
time.Sleep(2 * time.Second) | ||
os.WriteFile("/tmp/delete.txt", []byte("test"), 0777) | ||
time.Sleep(2 * time.Second) | ||
os.Remove("/tmp/delete.txt") | ||
time.Sleep(2 * time.Second) | ||
testA.mutex.Lock() | ||
if testA.expectedContent != "" { | ||
t.Errorf("failed in TestDeleteDynamicFile") | ||
} | ||
testA.mutex.Unlock() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.