-
Notifications
You must be signed in to change notification settings - Fork 0
feat: moved to multicluster-provider #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 34 commits
f4ce3f1
4999ab2
82ce421
70e5a05
c04cab2
b5a328d
903e39a
e84c1f7
9919cf0
3f5976f
fea6b34
b8f3ade
1be4f83
0c9ac2d
1aa7ca0
a5efb28
36eff27
907f251
c7193e2
b366f2b
98ab379
70b65c2
ad6be7a
e9b4c33
5c4741d
e3b5705
7d6d82c
330ffe4
282ef8b
5b62aa1
3ab0b6e
3225d75
d01584a
bcc07f3
988e7b7
b808fd2
1869a61
e8beffd
779f42c
f6bab1c
97cc1c0
4494be2
409185a
662bcef
e695399
73cc293
00c6e87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package cmd | |
import ( | ||
"context" | ||
"crypto/tls" | ||
"os" | ||
|
||
kcpapis "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1" | ||
kcpcore "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1" | ||
|
@@ -77,7 +78,20 @@ var listenCmd = &cobra.Command{ | |
Run: func(cmd *cobra.Command, args []string) { | ||
log.Info().Str("LogLevel", log.GetLevel().String()).Msg("Starting the Listener...") | ||
|
||
ctx := ctrl.SetupSignalHandler() | ||
// Set up signal handler and create a cancellable context for coordinated shutdown | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
// Error channel to distinguish error-triggered shutdown from normal signals | ||
errCh := make(chan error, 1) | ||
|
||
// Set up signal handling | ||
signalCtx := ctrl.SetupSignalHandler() | ||
go func() { | ||
<-signalCtx.Done() | ||
log.Info().Msg("received shutdown signal, initiating graceful shutdown") | ||
cancel() | ||
}() | ||
|
||
restCfg := ctrl.GetConfigOrDie() | ||
|
||
mgrOpts := ctrl.Options{ | ||
|
@@ -93,7 +107,8 @@ var listenCmd = &cobra.Command{ | |
Scheme: scheme, | ||
}) | ||
if err != nil { | ||
log.Fatal().Err(err).Msg("failed to create client from config") | ||
log.Error().Err(err).Msg("failed to create client from config") | ||
os.Exit(1) | ||
} | ||
|
||
reconcilerOpts := reconciler.ReconcilerOpts{ | ||
|
@@ -105,44 +120,65 @@ var listenCmd = &cobra.Command{ | |
} | ||
|
||
// Create the appropriate reconciler based on configuration | ||
var reconcilerInstance reconciler.CustomReconciler | ||
var reconcilerInstance reconciler.ControllerProvider | ||
if appCfg.EnableKcp { | ||
kcpReconciler, err := kcp.NewKCPReconciler(appCfg, reconcilerOpts, log) | ||
kcpManager, err := kcp.NewKCPManager(appCfg, reconcilerOpts, log) | ||
if err != nil { | ||
log.Fatal().Err(err).Msg("unable to create KCP reconciler") | ||
log.Error().Err(err).Msg("unable to create KCP manager") | ||
os.Exit(1) | ||
} | ||
reconcilerInstance = kcpManager | ||
|
||
// Start virtual workspace watching if path is configured | ||
if appCfg.Listener.VirtualWorkspacesConfigPath != "" { | ||
go func() { | ||
if err := kcpReconciler.StartVirtualWorkspaceWatching(ctx, appCfg.Listener.VirtualWorkspacesConfigPath); err != nil { | ||
log.Fatal().Err(err).Msg("failed to start virtual workspace watching") | ||
if err := kcpManager.StartVirtualWorkspaceWatching(ctx, appCfg.Listener.VirtualWorkspacesConfigPath); err != nil { | ||
log.Error().Err(err).Msg("virtual workspace watching failed, initiating graceful shutdown") | ||
select { | ||
case errCh <- err: | ||
default: | ||
} | ||
cancel() // Trigger coordinated shutdown | ||
} | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}() | ||
} | ||
|
||
reconcilerInstance = kcpReconciler | ||
} else { | ||
ioHandler, err := workspacefile.NewIOHandler(appCfg.OpenApiDefinitionsPath) | ||
if err != nil { | ||
log.Fatal().Err(err).Msg("unable to create IO handler") | ||
log.Error().Err(err).Msg("unable to create IO handler") | ||
os.Exit(1) | ||
} | ||
|
||
reconcilerInstance, err = clusteraccess.NewClusterAccessReconciler(ctx, appCfg, reconcilerOpts, ioHandler, apischema.NewResolver(log), log) | ||
if err != nil { | ||
log.Fatal().Err(err).Msg("unable to create cluster access reconciler") | ||
log.Error().Err(err).Msg("unable to create cluster access reconciler") | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
// Setup reconciler with its own manager and start everything | ||
// Use the original context for the manager - it will be cancelled if watcher fails | ||
if err := startManagerWithReconciler(ctx, reconcilerInstance); err != nil { | ||
log.Fatal().Err(err).Msg("failed to start manager with reconciler") | ||
log.Error().Err(err).Msg("failed to start manager with reconciler") | ||
os.Exit(1) | ||
} | ||
|
||
// Determine exit reason: error-triggered vs. normal signal | ||
select { | ||
case err := <-errCh: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tbh i am not fully happy with the context and error handling, maybe we find a better solution in the future There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can fix context propagation, but I am not sure what would you improve here in this select statement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Attention, untested: This could be an idea using Run: func(cmd *cobra.Command, args []string) {
log.Info().Str("LogLevel", log.GetLevel().String()).Msg("Starting the Listener...")
// Set up signal handling
signalCtx := ctrl.SetupSignalHandler()
ctx, cancel := context.WithCancel(signalCtx)
defer cancel()
restCfg := ctrl.GetConfigOrDie()
mgrOpts := ctrl.Options{
Scheme: scheme,
Metrics: metricsServerOptions,
WebhookServer: webhookServer,
HealthProbeBindAddress: defaultCfg.HealthProbeBindAddress,
LeaderElection: defaultCfg.LeaderElection.Enabled,
LeaderElectionID: "72231e1f.platform-mesh.io",
}
clt, err := client.New(restCfg, client.Options{
Scheme: scheme,
})
if err != nil {
log.Fatal().Err(err).Msg("failed to create client from config")
}
reconcilerOpts := reconciler.ReconcilerOpts{
Scheme: scheme,
Client: clt,
Config: restCfg,
ManagerOpts: mgrOpts,
OpenAPIDefinitionsPath: appCfg.OpenApiDefinitionsPath,
}
eg, eCtx := errgroup.WithContext(ctx)
// Create the appropriate reconciler based on configuration
var reconcilerInstance reconciler.ControllerProvider
if appCfg.EnableKcp {
kcpManager, err := kcp.NewKCPManager(appCfg, reconcilerOpts, log)
if err != nil {
log.Fatal().Err(err).Msg("unable to create KCP manager")
}
reconcilerInstance = kcpManager
// Start virtual workspace watching if path is configured
if appCfg.Listener.VirtualWorkspacesConfigPath != "" {
eg.Go(func() error {
if err := kcpManager.StartVirtualWorkspaceWatching(eCtx, appCfg.Listener.VirtualWorkspacesConfigPath); err != nil {
return err
}
return nil
})
}
} else {
ioHandler, err := workspacefile.NewIOHandler(appCfg.OpenApiDefinitionsPath)
if err != nil {
log.Fatal().Err(err).Msg("unable to create IO handler")
}
reconcilerInstance, err = clusteraccess.NewClusterAccessReconciler(ctx, appCfg, reconcilerOpts, ioHandler, apischema.NewResolver(log), log)
if err != nil {
log.Fatal().Err(err).Msg("unable to create cluster access reconciler")
}
}
// Setup reconciler with its own manager and start everything
// Use the original context for the manager - it will be cancelled if watcher fails
eg.Go(func() error {
if err := startManagerWithReconciler(eCtx, reconcilerInstance); err != nil {
log.Error().Err(err).Msg("failed to start manager with reconciler")
return err
}
return nil
})
err = eg.Wait()
if err != nil {
log.Fatal().Err(err).Msg("exiting due to critical component failure")
}
log.Info().Msg("graceful shutdown complete")
}, Maybe we don't even need our own context and can only use the signal context. The errgroup returns it's own context that is cancelled if one function returns with an error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will also do it in this issue: |
||
if err != nil { | ||
log.Error().Err(err).Msg("exiting due to critical component failure") | ||
os.Exit(1) | ||
} | ||
default: | ||
// Normal, graceful shutdown via signal | ||
log.Info().Msg("graceful shutdown complete") | ||
} | ||
}, | ||
} | ||
|
||
// startManagerWithReconciler handles the common manager setup and start operations | ||
func startManagerWithReconciler(ctx context.Context, reconciler reconciler.CustomReconciler) error { | ||
func startManagerWithReconciler(ctx context.Context, reconciler reconciler.ControllerProvider) error { | ||
mgr := reconciler.GetManager() | ||
|
||
if err := reconciler.SetupWithManager(mgr); err != nil { | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just out of curiosity: What is the reason to switch to
log.Error()
aslog.Fatal()
also das theos.Exit(1)
- is it the log level?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After your comment I double checked the behavior and log.Fatal does basically the same as log.Error + os.Exit, but it additionally it flushes any buffered messages.
Replaced log.Error + os.Exit with log.Fatal