Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(file-loader): Add recursive loading from sub-directories #5126

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion api/v1alpha1/envoygateway_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ type EnvoyGatewayResourceProvider struct {
// EnvoyGatewayFileResourceProvider defines configuration for the File Resource provider.
type EnvoyGatewayFileResourceProvider struct {
// Paths are the paths to a directory or file containing the resource configuration.
// Recursive subdirectories are not currently supported.
// The directories are scanned recursively to load resources from all sub-folders.
Paths []string `json:"paths"`
}

Expand Down
25 changes: 15 additions & 10 deletions internal/provider/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,19 @@ func (p *Provider) Start(ctx context.Context) error {
}
go p.startHealthProbeServer(ctx, readyzChecker)

initDirs, initFiles := path.ListDirsAndFiles(p.paths)
inputDirs, inputFiles := path.ListDirsAndFiles(p.paths)

// Initially load resources from paths on host.
if err := p.resourcesStore.LoadAndStore(initFiles.UnsortedList(), initDirs.UnsortedList()); err != nil {
allDirs, err := p.resourcesStore.LoadAndStore(inputFiles.UnsortedList(), inputDirs.UnsortedList())
if err != nil {
return fmt.Errorf("failed to load resources into store: %w", err)
}

allWatchedPaths := allDirs.Clone().Insert(p.paths...)

// Add paths to the watcher, and aggregate all path channels into one.
aggCh := make(chan fsnotify.Event)
for _, path := range p.paths {
for path := range allWatchedPaths {
if err := p.watcher.Add(path); err != nil {
p.logger.Error(err, "failed to add watch", "path", path)
} else {
Expand All @@ -94,8 +98,9 @@ func (p *Provider) Start(ctx context.Context) error {
}

p.ready.Store(true)
curDirs, curFiles := initDirs.Clone(), initFiles.Clone()
initFilesParent := path.GetParentDirs(initFiles.UnsortedList())
curDirs, curFiles := allDirs.Clone(), inputFiles.Clone()
inputFilesParent := path.GetParentDirs(inputFiles.UnsortedList())

for {
select {
case <-ctx.Done():
Expand All @@ -114,16 +119,16 @@ func (p *Provider) Start(ctx context.Context) error {
// temporary file when file is saved. So the watcher will only receive:
// - Create event, with name "filename~".
// - Remove event, with name "filename", but the file actually exist.
if initFilesParent.Has(filepath.Dir(event.Name)) {
if inputFilesParent.Has(filepath.Dir(event.Name)) {
p.logger.Info("file changed", "op", event.Op, "name", event.Name)

// For Write event, the file definitely exist.
if initFiles.Has(event.Name) && event.Has(fsnotify.Write) {
if inputFiles.Has(event.Name) && event.Has(fsnotify.Write) {
goto handle
}

// Iter over the watched files to see the different.
for f := range initFiles {
for f := range inputFiles {
_, err := os.Lstat(f)
if err != nil {
if os.IsNotExist(err) {
Expand All @@ -146,8 +151,8 @@ func (p *Provider) Start(ctx context.Context) error {

switch event.Op {
case fsnotify.Create, fsnotify.Write, fsnotify.Remove:
// Since we do not watch any events in the subdirectories, any events involving files
// modifications in current directory will trigger the event handling.
// Since we do not watch any events related to creation/deletion of subdirectories,
// any events involving files & folder modifications should trigger the event handling.
goto handle
default:
// do nothing
Expand Down
Loading