@@ -13,6 +13,7 @@ import (
13
13
"os"
14
14
"path/filepath"
15
15
"strings"
16
+ "sync"
16
17
"sync/atomic"
17
18
"time"
18
19
@@ -25,33 +26,45 @@ import (
25
26
"github.com/envoyproxy/gateway/internal/envoygateway/config"
26
27
"github.com/envoyproxy/gateway/internal/filewatcher"
27
28
"github.com/envoyproxy/gateway/internal/message"
29
+ "github.com/envoyproxy/gateway/internal/provider/kubernetes"
28
30
"github.com/envoyproxy/gateway/internal/utils/path"
29
31
)
30
32
31
33
type Provider struct {
32
- paths []string
33
- logger logr.Logger
34
- watcher filewatcher.FileWatcher
35
- resourcesStore * resourcesStore
36
- extensionManagerEnabled bool
34
+ paths []string
35
+ logger logr.Logger
36
+ watcher filewatcher.FileWatcher
37
+ resources * message.ProviderResources
38
+ reconciler * kubernetes.OfflineGatewayAPIReconciler
39
+ store * resourcesStore
40
+ status * StatusHandler
37
41
38
42
// ready indicates whether the provider can start watching filesystem events.
39
43
ready atomic.Bool
40
44
}
41
45
42
- func New (svr * config.Server , resources * message.ProviderResources ) (* Provider , error ) {
46
+ func New (ctx context. Context , svr * config.Server , resources * message.ProviderResources ) (* Provider , error ) {
43
47
logger := svr .Logger .Logger
44
48
paths := sets .New [string ]()
45
49
if svr .EnvoyGateway .Provider .Custom .Resource .File != nil {
46
50
paths .Insert (svr .EnvoyGateway .Provider .Custom .Resource .File .Paths ... )
47
51
}
48
52
53
+ // Create gateway-api offline reconciler.
54
+ statusHandler := NewStatusHandler (logger )
55
+ reconciler , err := kubernetes .NewOfflineGatewayAPIController (ctx , svr , statusHandler .Writer (), resources )
56
+ if err != nil {
57
+ return nil , fmt .Errorf ("failed to create offline gateway-api controller" )
58
+ }
59
+
49
60
return & Provider {
50
- paths : paths .UnsortedList (),
51
- logger : logger ,
52
- watcher : filewatcher .NewWatcher (),
53
- resourcesStore : newResourcesStore (svr .EnvoyGateway .Gateway .ControllerName , resources , logger ),
54
- extensionManagerEnabled : svr .EnvoyGateway .ExtensionManager != nil ,
61
+ paths : paths .UnsortedList (),
62
+ logger : logger ,
63
+ watcher : filewatcher .NewWatcher (),
64
+ resources : resources ,
65
+ reconciler : reconciler ,
66
+ store : newResourcesStore (svr .EnvoyGateway .Gateway .ControllerName , reconciler .Client , resources , logger ),
67
+ status : statusHandler ,
55
68
}, nil
56
69
}
57
70
@@ -73,13 +86,18 @@ func (p *Provider) Start(ctx context.Context) error {
73
86
}
74
87
go p .startHealthProbeServer (ctx , readyzChecker )
75
88
76
- // Subscribe resources status.
77
- p .subscribeAndUpdateStatus (ctx )
89
+ // Offline controller should be started before initial resources load.
90
+ // Nor we may lose some messages from controller.
91
+ wg := new (sync.WaitGroup )
92
+ wg .Add (2 )
93
+ go p .startReconciling (ctx , wg )
94
+ go p .status .Start (ctx , wg )
95
+ wg .Wait ()
78
96
79
97
initDirs , initFiles := path .ListDirsAndFiles (p .paths )
80
- // Initially load resources from paths on host .
81
- if err := p .resourcesStore . LoadAndStore ( initFiles .UnsortedList (), initDirs .UnsortedList ()); err != nil {
82
- return fmt . Errorf ( "failed to load resources into store: %w" , err )
98
+ // Initially load resources.
99
+ if err := p .store . ReloadAll ( ctx , initFiles .UnsortedList (), initDirs .UnsortedList ()); err != nil {
100
+ p . logger . Error ( err , "failed to reload resources initially" )
83
101
}
84
102
85
103
// Add paths to the watcher, and aggregate all path channels into one.
@@ -150,18 +168,31 @@ func (p *Provider) Start(ctx context.Context) error {
150
168
}
151
169
p .logger .Info ("file changed" , "op" , event .Op , "name" , event .Name , "dir" , filepath .Dir (event .Name ))
152
170
153
- switch event .Op {
154
- case fsnotify .Create , fsnotify .Write , fsnotify .Remove :
155
- // Since we do not watch any events in the subdirectories, any events involving files
156
- // modifications in current directory will trigger the event handling.
157
- goto handle
158
- default :
159
- // do nothing
160
- continue
171
+ handle:
172
+ if err := p .store .ReloadAll (ctx , curFiles .UnsortedList (), curDirs .UnsortedList ()); err != nil {
173
+ p .logger .Error (err , "error when reload resources" , "op" , event .Op , "name" , event .Name )
161
174
}
175
+ }
176
+ }
177
+ }
162
178
163
- handle:
164
- p .resourcesStore .HandleEvent (curFiles .UnsortedList (), curDirs .UnsortedList ())
179
+ // startReconciling starts reconcile on offline controller when receiving signal from resources store.
180
+ func (p * Provider ) startReconciling (ctx context.Context , ready * sync.WaitGroup ) {
181
+ p .logger .Info ("start reconciling" )
182
+ defer p .logger .Info ("stop reconciling" )
183
+ ready .Done ()
184
+
185
+ for {
186
+ select {
187
+ case rid := <- p .store .reconcile :
188
+ p .logger .Info ("start reconcile" , "id" , rid , "time" , time .Now ())
189
+ if err := p .reconciler .Reconcile (ctx ); err != nil {
190
+ p .logger .Error (err , "failed to reconcile" , "id" , rid )
191
+ }
192
+ p .logger .Info ("reconcile finished" , "id" , rid , "time" , time .Now ())
193
+
194
+ case <- ctx .Done ():
195
+ return
165
196
}
166
197
}
167
198
}
0 commit comments