Skip to content

Commit b6149b1

Browse files
dilyevskyclaude
andcommitted
[apiserver] Add WithSkipBuiltinControllers option
Add option to skip built-in controllers (Proxy, TunnelNode, Gateway, etc.) and the APIService wait. This allows using the apiserver as a library for custom apiservers that register their own resource types without needing the full controller set. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 19d27c9 commit b6149b1

File tree

1 file changed

+151
-137
lines changed

1 file changed

+151
-137
lines changed

pkg/apiserver/manager.go

Lines changed: 151 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -173,28 +173,29 @@ func (c *certSource) GetCertificate(*tls.ClientHelloInfo) (*tls.Certificate, err
173173
type Option func(*options)
174174

175175
type options struct {
176-
clientConfig *rest.Config
177-
enableSimpleAuth bool
178-
enableInClusterAuth bool
179-
sqlitePath string
180-
sqliteConnArgs map[string]string
181-
certPairName, certDir string
182-
enableKubeAPI bool
183-
controllerNames []string
184-
additionalControllers []CreateController
185-
gcInterval time.Duration
186-
jwtPublicKey []byte
187-
jwtPrivateKey []byte
188-
jwtRefreshThreshold time.Duration
189-
jwksHost string
190-
jwksPort int
191-
resources []resource.Object
192-
proxyIPAM tunnet.IPAM
193-
agentIPAM tunnet.IPAM
194-
vniPool *vni.VNIPool
195-
tokenValidator token.Validator
196-
tokenIssuer token.TokenIssuer
197-
openAPIDefinitions common.GetOpenAPIDefinitions
176+
clientConfig *rest.Config
177+
enableSimpleAuth bool
178+
enableInClusterAuth bool
179+
sqlitePath string
180+
sqliteConnArgs map[string]string
181+
certPairName, certDir string
182+
enableKubeAPI bool
183+
controllerNames []string
184+
additionalControllers []CreateController
185+
skipBuiltinControllers bool
186+
gcInterval time.Duration
187+
jwtPublicKey []byte
188+
jwtPrivateKey []byte
189+
jwtRefreshThreshold time.Duration
190+
jwksHost string
191+
jwksPort int
192+
resources []resource.Object
193+
proxyIPAM tunnet.IPAM
194+
agentIPAM tunnet.IPAM
195+
vniPool *vni.VNIPool
196+
tokenValidator token.Validator
197+
tokenIssuer token.TokenIssuer
198+
openAPIDefinitions common.GetOpenAPIDefinitions
198199
}
199200

200201
// WithJWTKeys sets the JWT key pair.
@@ -367,6 +368,15 @@ func WithVNIPool(pool *vni.VNIPool) Option {
367368
}
368369
}
369370

371+
// WithSkipBuiltinControllers skips the built-in controllers (Proxy, TunnelNode, Gateway, etc.)
372+
// and the APIService wait. Use this when you only need the apiserver functionality without
373+
// the full controller set, e.g., for custom apiservers that register their own resource types.
374+
func WithSkipBuiltinControllers() Option {
375+
return func(o *options) {
376+
o.skipBuiltinControllers = true
377+
}
378+
}
379+
370380
func defaultResources() []resource.Object {
371381
// Higher versions need to be registered first as storage resources.
372382
return []resource.Object{
@@ -530,129 +540,133 @@ func (m *Manager) Start(
530540
return fmt.Errorf("unable to start manager: %v", err)
531541
}
532542

533-
log.Infof("Starting API server built-in controllers")
534-
535-
if err := waitForAPIService(ctx, m.manager.GetConfig(), corev1alpha2.GroupVersion, 2*time.Minute); err != nil {
536-
return fmt.Errorf("failed to wait for APIService %s: %v", corev1alpha2.GroupVersion.Group, err)
537-
}
538-
539-
// Start the Status Runner to write Gateway API resource statuses back to the API server.
540-
// This subscribes to status updates from the gateway translation pipeline and writes
541-
// them back to Kubernetes.
542-
log.Infof("Starting Gateway API Status Runner")
543-
statusRunner := statusrunner.New(&statusrunner.Config{
544-
Client: m.manager.GetClient(),
545-
ProviderResources: gwResources,
546-
})
547-
if err := statusRunner.Start(ctx); err != nil {
548-
return fmt.Errorf("failed to start status runner: %v", err)
549-
}
550-
551543
ctx, cancel := context.WithCancel(ctx)
552544
defer cancel()
553545
g, ctx := errgroup.WithContext(ctx)
554546

555-
log.Infof("Registering Proxy controller")
556-
if err := controllers.NewProxyReconciler(
557-
ctx,
558-
m.manager.GetClient(),
559-
gwResources,
560-
dOpts.proxyIPAM,
561-
cancel,
562-
).SetupWithManager(ctx, m.manager); err != nil {
563-
return fmt.Errorf("failed to set up Proxy controller: %v", err)
564-
}
565-
566-
// Legacy v1alpha1 TunnelNode controller
567-
log.Infof("Registering TunnelNode controller")
568-
var tunnelNodeValidator token.Validator
569-
if dOpts.tokenValidator != nil {
570-
tunnelNodeValidator = dOpts.tokenValidator
571-
} else {
572-
var err error
573-
tunnelNodeValidator, err = token.NewInMemoryValidator(dOpts.jwtPublicKey)
574-
if err != nil {
575-
return fmt.Errorf("failed to create tunnel node validator: %v", err)
547+
// Skip built-in controllers if requested. This is useful for custom apiservers
548+
// that only need the apiserver functionality without the full controller set.
549+
if !dOpts.skipBuiltinControllers {
550+
log.Infof("Starting API server built-in controllers")
551+
552+
if err := waitForAPIService(ctx, m.manager.GetConfig(), corev1alpha2.GroupVersion, 2*time.Minute); err != nil {
553+
return fmt.Errorf("failed to wait for APIService %s: %v", corev1alpha2.GroupVersion.Group, err)
576554
}
577-
}
578-
var tunnelNodeIssuer token.TokenIssuer
579-
if dOpts.tokenIssuer != nil {
580-
tunnelNodeIssuer = dOpts.tokenIssuer
581-
} else {
582-
var err error
583-
tunnelNodeIssuer, err = token.NewIssuer(dOpts.jwtPrivateKey)
584-
if err != nil {
585-
return fmt.Errorf("failed to create tunnel node issuer: %v", err)
586-
}
587-
}
588-
tunnelNodeReconciler := controllers.NewTunnelNodeReconciler(
589-
m.manager.GetClient(),
590-
tunnelNodeValidator,
591-
tunnelNodeIssuer,
592-
dOpts.jwksHost,
593-
dOpts.jwksPort,
594-
dOpts.jwtRefreshThreshold,
595-
dOpts.agentIPAM,
596-
apoxynet.NewIPAMv4(context.Background()),
597-
)
598-
if err := tunnelNodeReconciler.SetupWithManager(m.manager); err != nil {
599-
return fmt.Errorf("failed to set up TunnelNode controller: %v", err)
600-
}
601-
g.Go(func() error {
602-
if err := tunnelNodeReconciler.ServeJWKS(ctx); err != nil {
603-
log.Errorf("failed to serve JWKS: %v", err)
604-
return fmt.Errorf("failed to serve JWKS: %v", err)
555+
556+
// Start the Status Runner to write Gateway API resource statuses back to the API server.
557+
// This subscribes to status updates from the gateway translation pipeline and writes
558+
// them back to Kubernetes.
559+
log.Infof("Starting Gateway API Status Runner")
560+
statusRunner := statusrunner.New(&statusrunner.Config{
561+
Client: m.manager.GetClient(),
562+
ProviderResources: gwResources,
563+
})
564+
if err := statusRunner.Start(ctx); err != nil {
565+
return fmt.Errorf("failed to start status runner: %v", err)
605566
}
606-
return nil
607-
})
608567

609-
log.Infof("Registering Tunnel controller")
610-
tunnelReconciler := controllers.NewTunnelReconciler(m.manager.GetClient())
611-
if err := tunnelReconciler.SetupWithManager(m.manager); err != nil {
612-
return fmt.Errorf("failed to set up Tunnel controller: %v", err)
613-
}
568+
log.Infof("Registering Proxy controller")
569+
if err := controllers.NewProxyReconciler(
570+
ctx,
571+
m.manager.GetClient(),
572+
gwResources,
573+
dOpts.proxyIPAM,
574+
cancel,
575+
).SetupWithManager(ctx, m.manager); err != nil {
576+
return fmt.Errorf("failed to set up Proxy controller: %v", err)
577+
}
614578

615-
log.Infof("Registering TunnelAgent controller")
616-
tunnelAgentReconciler := controllers.NewTunnelAgentReconciler(
617-
m.manager.GetClient(),
618-
dOpts.agentIPAM,
619-
dOpts.vniPool,
620-
)
621-
if err := tunnelAgentReconciler.SetupWithManager(ctx, m.manager); err != nil {
622-
return fmt.Errorf("failed to set up TunnelAgent controller: %v", err)
623-
}
624-
625-
log.Infof("Registering Gateway controller")
626-
gwOpts := []gateway.Option{}
627-
if dOpts.enableKubeAPI {
628-
gwOpts = append(gwOpts, gateway.WithKubeAPI())
629-
}
630-
if len(dOpts.controllerNames) > 0 {
631-
gwOpts = append(gwOpts, gateway.WithControllerNames(dOpts.controllerNames...))
632-
}
633-
if err := gateway.NewGatewayReconciler(
634-
m.manager.GetClient(),
635-
gwResources,
636-
gwOpts...,
637-
).SetupWithManager(ctx, m.manager); err != nil {
638-
return fmt.Errorf("failed to set up Gateway controller: %v", err)
639-
}
640-
641-
log.Infof("Registering EdgeFunction controller")
642-
if err := extensionscontroller.NewEdgeFunctionReconciler(
643-
m.manager.GetClient(),
644-
m.manager.GetScheme(),
645-
tc,
646-
).SetupWithManager(ctx, m.manager); err != nil {
647-
return fmt.Errorf("failed to set up EdgeFunction controller: %v", err)
648-
}
649-
if err := extensionscontroller.NewEdgeFunctionRevisionGCReconciler(
650-
m.manager.GetClient(),
651-
m.manager.GetScheme(),
652-
tc,
653-
dOpts.gcInterval,
654-
).SetupWithManager(ctx, m.manager); err != nil {
655-
return fmt.Errorf("failed to set up EdgeFunctionRevision GC controller: %v", err)
579+
// Legacy v1alpha1 TunnelNode controller
580+
log.Infof("Registering TunnelNode controller")
581+
var tunnelNodeValidator token.Validator
582+
if dOpts.tokenValidator != nil {
583+
tunnelNodeValidator = dOpts.tokenValidator
584+
} else {
585+
var err error
586+
tunnelNodeValidator, err = token.NewInMemoryValidator(dOpts.jwtPublicKey)
587+
if err != nil {
588+
return fmt.Errorf("failed to create tunnel node validator: %v", err)
589+
}
590+
}
591+
var tunnelNodeIssuer token.TokenIssuer
592+
if dOpts.tokenIssuer != nil {
593+
tunnelNodeIssuer = dOpts.tokenIssuer
594+
} else {
595+
var err error
596+
tunnelNodeIssuer, err = token.NewIssuer(dOpts.jwtPrivateKey)
597+
if err != nil {
598+
return fmt.Errorf("failed to create tunnel node issuer: %v", err)
599+
}
600+
}
601+
tunnelNodeReconciler := controllers.NewTunnelNodeReconciler(
602+
m.manager.GetClient(),
603+
tunnelNodeValidator,
604+
tunnelNodeIssuer,
605+
dOpts.jwksHost,
606+
dOpts.jwksPort,
607+
dOpts.jwtRefreshThreshold,
608+
dOpts.agentIPAM,
609+
apoxynet.NewIPAMv4(context.Background()),
610+
)
611+
if err := tunnelNodeReconciler.SetupWithManager(m.manager); err != nil {
612+
return fmt.Errorf("failed to set up TunnelNode controller: %v", err)
613+
}
614+
g.Go(func() error {
615+
if err := tunnelNodeReconciler.ServeJWKS(ctx); err != nil {
616+
log.Errorf("failed to serve JWKS: %v", err)
617+
return fmt.Errorf("failed to serve JWKS: %v", err)
618+
}
619+
return nil
620+
})
621+
622+
log.Infof("Registering Tunnel controller")
623+
tunnelReconciler := controllers.NewTunnelReconciler(m.manager.GetClient())
624+
if err := tunnelReconciler.SetupWithManager(m.manager); err != nil {
625+
return fmt.Errorf("failed to set up Tunnel controller: %v", err)
626+
}
627+
628+
log.Infof("Registering TunnelAgent controller")
629+
tunnelAgentReconciler := controllers.NewTunnelAgentReconciler(
630+
m.manager.GetClient(),
631+
dOpts.agentIPAM,
632+
dOpts.vniPool,
633+
)
634+
if err := tunnelAgentReconciler.SetupWithManager(ctx, m.manager); err != nil {
635+
return fmt.Errorf("failed to set up TunnelAgent controller: %v", err)
636+
}
637+
638+
log.Infof("Registering Gateway controller")
639+
gwOpts := []gateway.Option{}
640+
if dOpts.enableKubeAPI {
641+
gwOpts = append(gwOpts, gateway.WithKubeAPI())
642+
}
643+
if len(dOpts.controllerNames) > 0 {
644+
gwOpts = append(gwOpts, gateway.WithControllerNames(dOpts.controllerNames...))
645+
}
646+
if err := gateway.NewGatewayReconciler(
647+
m.manager.GetClient(),
648+
gwResources,
649+
gwOpts...,
650+
).SetupWithManager(ctx, m.manager); err != nil {
651+
return fmt.Errorf("failed to set up Gateway controller: %v", err)
652+
}
653+
654+
log.Infof("Registering EdgeFunction controller")
655+
if err := extensionscontroller.NewEdgeFunctionReconciler(
656+
m.manager.GetClient(),
657+
m.manager.GetScheme(),
658+
tc,
659+
).SetupWithManager(ctx, m.manager); err != nil {
660+
return fmt.Errorf("failed to set up EdgeFunction controller: %v", err)
661+
}
662+
if err := extensionscontroller.NewEdgeFunctionRevisionGCReconciler(
663+
m.manager.GetClient(),
664+
m.manager.GetScheme(),
665+
tc,
666+
dOpts.gcInterval,
667+
).SetupWithManager(ctx, m.manager); err != nil {
668+
return fmt.Errorf("failed to set up EdgeFunctionRevision GC controller: %v", err)
669+
}
656670
}
657671

658672
if len(dOpts.additionalControllers) > 0 {

0 commit comments

Comments
 (0)