package multiclustermanager import ( "context" "fmt" "net" "net/http" "sync" "time" "github.com/rancher/norman/types" "github.com/rancher/rancher/pkg/features" "github.com/rancher/rancher/pkg/wrangler" "k8s.io/client-go/kubernetes" ) type DeferredServer struct { sync.RWMutex wrangler *wrangler.Context opts *Options mcm *mcm } func NewDeferredServer(wrangler *wrangler.Context, opts *Options) *DeferredServer { return &DeferredServer{ wrangler: wrangler, opts: opts, } } func (s *DeferredServer) Wait(ctx context.Context) { if !features.MCM.Enabled() { return } for { s.Lock() if s.mcm == nil { s.Unlock() select { case <-time.After(500 * time.Millisecond): continue case <-ctx.Done(): return } } s.Unlock() s.mcm.Wait(ctx) break } } func (s *DeferredServer) NormanSchemas() *types.Schemas { mcm := s.getMCM() if mcm == nil { return nil } return mcm.NormanSchemas() } func (s *DeferredServer) Start(ctx context.Context) error { s.Lock() defer s.Unlock() if s.mcm != nil { return nil } var ( mcm *mcm err error ) err = s.wrangler.StartWithTransaction(ctx, func(ctx context.Context) error { mcm, err = newMCM(ctx, s.wrangler, s.opts) if err != nil { return err } return mcm.Start(ctx) }) if mcm != nil { // always start, even on error mcm.started(ctx) } if err != nil { return err } s.mcm = mcm go func() { <-ctx.Done() s.Lock() defer s.Unlock() s.mcm = nil }() return nil } func (s *DeferredServer) getMCM() *mcm { s.RLock() defer s.RUnlock() return s.mcm } func (s *DeferredServer) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { mcm := s.getMCM() if mcm == nil { next.ServeHTTP(rw, req) return } mcm.Middleware(next).ServeHTTP(rw, req) }) } func (s *DeferredServer) ClusterDialer(clusterID string) func(ctx context.Context, network, address string) (net.Conn, error) { return func(ctx context.Context, network, address string) (net.Conn, error) { mcm := s.getMCM() if mcm == nil { return nil, fmt.Errorf("failed to find cluster %s", clusterID) } dialer, err := mcm.ScaledContext.Dialer.ClusterDialer(clusterID, true) if err != nil { return nil, err } return dialer(ctx, network, address) } } func (s *DeferredServer) K8sClient(clusterName string) (kubernetes.Interface, error) { mcm := s.getMCM() if mcm == nil { return nil, nil } clusterContext, err := mcm.clusterManager.UserContextNoControllers(clusterName) if err != nil { return nil, err } return clusterContext.K8sClient, nil }