@@ -10,11 +10,13 @@ import (
1010 "github.com/cilium/hive/cell"
1111 "github.com/cilium/hive/job"
1212 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+ "k8s.io/client-go/tools/cache"
1314 "k8s.io/client-go/util/workqueue"
1415 mcsapiv1alpha1 "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"
1516
1617 "github.com/cilium/cilium/pkg/clustermesh/mcsapi/types"
1718 mcsapitypes "github.com/cilium/cilium/pkg/clustermesh/mcsapi/types"
19+ cmnamespace "github.com/cilium/cilium/pkg/clustermesh/namespace"
1820 cmtypes "github.com/cilium/cilium/pkg/clustermesh/types"
1921 "github.com/cilium/cilium/pkg/k8s/client"
2022 "github.com/cilium/cilium/pkg/k8s/resource"
@@ -57,6 +59,13 @@ type ServiceExportSyncParameters struct {
5759 Services resource.Resource [* slim_corev1.Service ]
5860
5961 SyncCallback ServiceExportSyncCallback `optional:"true"`
62+
63+ // NamespaceManager is used to determine if a namespace is global.
64+ // Optional - if not provided, namespace filtering is disabled.
65+ NamespaceManager cmnamespace.Manager `optional:"true"`
66+ // Namespaces is the resource for watching namespace events.
67+ // Optional - if not provided, namespace filtering is disabled.
68+ Namespaces resource.Resource [* slim_corev1.Namespace ] `optional:"true"`
6069}
6170
6271func registerServiceExportSync (jg job.Group , cfg ServiceExportSyncParameters ) {
@@ -85,6 +94,9 @@ func registerServiceExportSync(jg job.Group, cfg ServiceExportSyncParameters) {
8594
8695 store : store ,
8796 syncCallback : cfg .SyncCallback ,
97+
98+ namespaceManager : cfg .NamespaceManager ,
99+ namespaces : cfg .Namespaces ,
88100 }).loop (ctx )
89101 return nil
90102 },
@@ -110,6 +122,10 @@ type serviceExportSync struct {
110122
111123 store store.SyncStore
112124 syncCallback ServiceExportSyncCallback
125+
126+ // Namespace filtering support
127+ namespaceManager cmnamespace.Manager
128+ namespaces resource.Resource [* slim_corev1.Namespace ]
113129}
114130
115131func (s * serviceExportSync ) loop (ctx context.Context ) {
@@ -151,6 +167,47 @@ func (s *serviceExportSync) loop(ctx context.Context) {
151167 return
152168 }
153169
170+ // Setup namespace events channel if namespace filtering is enabled
171+ var namespaceEvents <- chan resource.Event [* slim_corev1.Namespace ]
172+ namespaceFilteringEnabled := s .namespaceManager != nil && s .namespaces != nil
173+ if namespaceFilteringEnabled {
174+ s .logger .Info ("Namespace filtering is enabled for service export sync" )
175+ namespaceEvents = s .namespaces .Events (ctx )
176+ } else {
177+ s .logger .Info ("Namespace filtering is disabled for service export sync" )
178+ }
179+
180+ // isNamespaceGlobal checks if the namespace is global. If namespace filtering
181+ // is disabled, all namespaces are considered global.
182+ isNamespaceGlobal := func (namespace string ) bool {
183+ if ! namespaceFilteringEnabled {
184+ return true
185+ }
186+ isGlobal , err := s .namespaceManager .IsGlobalNamespaceByName (namespace )
187+ if err != nil {
188+ s .logger .Warn ("Failed to determine if namespace is global, assuming not global" ,
189+ logfields .Error , err ,
190+ logfields .K8sNamespace , namespace ,
191+ )
192+ return false
193+ }
194+ return isGlobal
195+ }
196+
197+ // syncServiceExport syncs a service export based on namespace global status
198+ syncServiceExport := func (key resource.Key ) error {
199+ // Check namespace global status before syncing
200+ if ! isNamespaceGlobal (key .Namespace ) {
201+ s .logger .Debug ("Skipping service export sync for non-global namespace" ,
202+ logfields .K8sSvcName , key .Name ,
203+ logfields .K8sNamespace , key .Namespace ,
204+ )
205+ // Delete the service export from kvstore if it exists (namespace may have become non-global)
206+ return s .store .DeleteKey (ctx , types .NewEmptyMCSAPIServiceSpec (s .clusterName , key .Namespace , key .Name ))
207+ }
208+ return s .syncMCSAPIServiceSpec (ctx , serviceStore , serviceExportStore , key )
209+ }
210+
154211 servicesSynced , serviceExportsSynced := false , false
155212 for serviceEvents != nil || serviceExportsEvents != nil {
156213 select {
@@ -169,8 +226,7 @@ func (s *serviceExportSync) loop(ctx context.Context) {
169226 continue
170227 }
171228
172- ev .Done (s .syncMCSAPIServiceSpec (ctx ,
173- serviceStore , serviceExportStore , ev .Key ))
229+ ev .Done (syncServiceExport (ev .Key ))
174230
175231 case ev , ok := <- serviceExportsEvents :
176232 if ! ok {
@@ -187,8 +243,53 @@ func (s *serviceExportSync) loop(ctx context.Context) {
187243 continue
188244 }
189245
190- ev .Done (s .syncMCSAPIServiceSpec (ctx ,
191- serviceStore , serviceExportStore , ev .Key ))
246+ ev .Done (syncServiceExport (ev .Key ))
247+
248+ case ev , ok := <- namespaceEvents :
249+ if ! ok {
250+ s .logger .Info ("Namespace event channel closed, ignoring future namespace events" )
251+ namespaceEvents = nil
252+ continue
253+ }
254+ ev .Done (nil )
255+
256+ if ev .Kind == resource .Sync {
257+ continue
258+ }
259+
260+ // Handle namespace changes - resync all service exports in this namespace
261+ if ev .Object == nil {
262+ continue
263+ }
264+
265+ nsName := ev .Key .Name
266+ isGlobal := s .namespaceManager .IsGlobalNamespaceByObject (ev .Object )
267+
268+ s .logger .Info ("Namespace global status changed, resyncing service exports" ,
269+ logfields .K8sNamespace , nsName ,
270+ "isGlobal" , isGlobal ,
271+ )
272+
273+ // Get all service exports in this namespace and resync them
274+ svcExports , err := serviceExportStore .ByIndex (cache .NamespaceIndex , nsName )
275+ if err != nil {
276+ s .logger .Warn ("Failed to list service exports for namespace update" ,
277+ logfields .Error , err ,
278+ logfields .K8sNamespace , nsName ,
279+ )
280+ continue
281+ }
282+
283+ for _ , svcExport := range svcExports {
284+ key := resource.Key {Namespace : svcExport .Namespace , Name : svcExport .Name }
285+ if ev .Kind == resource .Delete || ! isGlobal {
286+ // Namespace deleted or no longer global - delete all service exports
287+ s .store .DeleteKey (ctx , types .NewEmptyMCSAPIServiceSpec (s .clusterName , key .Namespace , key .Name ))
288+ } else {
289+ // Namespace became global - upsert service exports
290+ s .syncMCSAPIServiceSpec (ctx , serviceStore , serviceExportStore , key )
291+ }
292+ }
192293 }
193294 }
194295}
0 commit comments