@@ -21,9 +21,16 @@ import (
2121 "context"
2222 "crypto/tls"
2323 "crypto/x509"
24+ "encoding/json"
2425 "encoding/pem"
2526 "fmt"
2627 configaggregate "github.com/apache/dubbo-kubernetes/dubbod/planet/pkg/config/aggregate"
28+ "github.com/apache/dubbo-kubernetes/dubbod/planet/pkg/config/kube/gateway"
29+ "github.com/apache/dubbo-kubernetes/dubbod/planet/pkg/features"
30+ "github.com/apache/dubbo-kubernetes/dubbod/planet/pkg/leaderelection"
31+ "github.com/apache/dubbo-kubernetes/dubbod/planet/pkg/leaderelection/k8sleaderelection/k8sresourcelock"
32+ "github.com/apache/dubbo-kubernetes/pkg/config/schema/gvr"
33+ "k8s.io/apimachinery/pkg/api/errors"
2734 "net/url"
2835 "strings"
2936
@@ -59,7 +66,9 @@ func (s *Server) makeKubeConfigController(args *PlanetArgs) *crdclient.Client {
5966 }
6067
6168 schemas := collections .Planet
62-
69+ if features .EnableGatewayAPI {
70+ schemas = collections .PlanetGatewayAPI ()
71+ }
6372 return crdclient .NewForSchemas (s .kubeClient , opts , schemas )
6473}
6574
@@ -69,6 +78,72 @@ func (s *Server) initK8SConfigStore(args *PlanetArgs) error {
6978 }
7079 configController := s .makeKubeConfigController (args )
7180 s .ConfigStores = append (s .ConfigStores , configController )
81+
82+ if features .EnableGatewayAPI {
83+ if s .statusManager == nil && features .EnableGatewayAPIStatus {
84+ s .initStatusManager (args )
85+ }
86+ args .RegistryOptions .KubeOptions .KrtDebugger = args .KrtDebugger
87+ gwc := gateway .NewController (s .kubeClient , s .kubeClient .CrdWatcher ().WaitForCRD , args .RegistryOptions .KubeOptions , s .XDSServer )
88+ s .environment .GatewayAPIController = gwc
89+ s .ConfigStores = append (s .ConfigStores , s .environment .GatewayAPIController )
90+
91+ // Use a channel to signal activation of per-revision status writer
92+ activatePerRevisionStatusWriterCh := make (chan struct {})
93+ s .checkAndRunNonRevisionLeaderElectionIfRequired (args , activatePerRevisionStatusWriterCh )
94+
95+ s .addTerminatingStartFunc ("gateway status" , func (stop <- chan struct {}) error {
96+ leaderelection .
97+ NewPerRevisionLeaderElection (args .Namespace , args .PodName , leaderelection .GatewayStatusController , args .Revision , s .kubeClient ).
98+ AddRunFunction (func (leaderStop <- chan struct {}) {
99+ log .Infof ("waiting for gateway status writer activation" )
100+ <- activatePerRevisionStatusWriterCh
101+ log .Infof ("Starting gateway status writer for revision: %s" , args .Revision )
102+ gwc .SetStatusWrite (true , s .statusManager )
103+
104+ // Trigger a push so we can recompute status
105+ s .XDSServer .ConfigUpdate (& model.PushRequest {
106+ Full : true ,
107+ Reason : model .NewReasonStats (model .GlobalUpdate ),
108+ Forced : true ,
109+ })
110+ <- leaderStop
111+ log .Infof ("Stopping gateway status writer" )
112+ gwc .SetStatusWrite (false , nil )
113+ }).
114+ Run (stop )
115+ return nil
116+ })
117+ if features .EnableGatewayAPIDeploymentController {
118+ s .addTerminatingStartFunc ("gateway deployment controller" , func (stop <- chan struct {}) error {
119+ leaderelection .
120+ NewPerRevisionLeaderElection (args .Namespace , args .PodName , leaderelection .GatewayDeploymentController , args .Revision , s .kubeClient ).
121+ AddRunFunction (func (leaderStop <- chan struct {}) {
122+ // We can only run this if the Gateway CRD is created
123+ if s .kubeClient .CrdWatcher ().WaitForCRD (gvr .KubernetesGateway , leaderStop ) {
124+ controller := gateway .NewDeploymentController (s .kubeClient , s .clusterID , s .environment ,
125+ s .webhookInfo .getWebhookConfig , s .webhookInfo .addHandler , nil , args .Revision , args .Namespace )
126+ // Start informers again. This fixes the case where informers for namespace do not start,
127+ // as we create them only after acquiring the leader lock
128+ // Note: stop here should be the overall pilot stop, NOT the leader election stop. We are
129+ // basically lazy loading the informer, if we stop it when we lose the lock we will never
130+ // recreate it again.
131+ s .kubeClient .RunAndWait (stop )
132+ // TODO tag watcher
133+ controller .Run (leaderStop )
134+ }
135+ }).
136+ Run (stop )
137+ return nil
138+ })
139+ }
140+ }
141+ var err error
142+ s .RWConfigStore , err = configaggregate .MakeWriteableCache (s .ConfigStores , configController )
143+ if err != nil {
144+ return err
145+ }
146+
72147 s .XDSServer .ConfigUpdate (& model.PushRequest {
73148 Full : true ,
74149 Reason : model .NewReasonStats (model .GlobalUpdate ),
@@ -181,9 +256,6 @@ func (s *Server) initConfigController(args *PlanetArgs) error {
181256 }
182257 }
183258
184- // TODO ingress controller
185- // TODO addTerminatingStartFunc
186-
187259 // Wrap the config controller with a cache.
188260 aggregateConfigController , err := configaggregate .MakeCache (s .ConfigStores )
189261 if err != nil {
@@ -298,3 +370,60 @@ func (s *Server) getRootCertFromSecret(name, namespace string) (*dubboCredential
298370 }
299371 return kube .ExtractRoot (secret .Data )
300372}
373+
374+ func (s * Server ) checkAndRunNonRevisionLeaderElectionIfRequired (args * PlanetArgs , activateCh chan struct {}) {
375+ cm , err := s .kubeClient .Kube ().CoreV1 ().ConfigMaps (args .Namespace ).Get (context .Background (), leaderelection .GatewayStatusController , v1.GetOptions {})
376+
377+ if errors .IsNotFound (err ) {
378+ // ConfigMap does not exist, so per-revision leader election should be active
379+ close (activateCh )
380+ return
381+ }
382+ leaderAnn , ok := cm .Annotations [k8sresourcelock .LeaderElectionRecordAnnotationKey ]
383+ if ok {
384+ var leaderInfo struct {
385+ HolderIdentity string `json:"holderIdentity"`
386+ }
387+ if err := json .Unmarshal ([]byte (leaderAnn ), & leaderInfo ); err == nil {
388+ if leaderInfo .HolderIdentity != "" {
389+ // Non-revision leader election should run, per-revision should be waiting for activation
390+ s .addTerminatingStartFunc ("gateway status" , func (stop <- chan struct {}) error {
391+ secondStop := make (chan struct {})
392+ // if stop closes, ensure secondStop closes too
393+ go func () {
394+ <- stop
395+ select {
396+ case <- secondStop :
397+ default :
398+ close (secondStop )
399+ }
400+ }()
401+ leaderelection .
402+ NewLeaderElection (args .Namespace , args .PodName , leaderelection .GatewayStatusController , args .Revision , s .kubeClient ).
403+ AddRunFunction (func (leaderStop <- chan struct {}) {
404+ // now that we have the leader lock, we can activate the per-revision status writer
405+ // first close the activateCh channel if it is not already closed
406+ log .Infof ("Activating gateway status writer" )
407+ select {
408+ case <- activateCh :
409+ // Channel already closed, do nothing
410+ default :
411+ close (activateCh )
412+ }
413+ // now end this lease itself
414+ select {
415+ case <- secondStop :
416+ default :
417+ close (secondStop )
418+ }
419+ }).
420+ Run (secondStop )
421+ return nil
422+ })
423+ return
424+ }
425+ }
426+ }
427+ // If annotation missing or holderIdentity is blank, per-revision leader election should be active
428+ close (activateCh )
429+ }
0 commit comments