-
Notifications
You must be signed in to change notification settings - Fork 260
CFE-866: Add secret manager for routes to consume secret_monitor #1626
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
Merged
openshift-merge-bot
merged 1 commit into
openshift:master
from
chiragkyal:feature/secret-manager
Apr 25, 2024
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package fake | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| corev1 "k8s.io/api/core/v1" | ||
| "k8s.io/client-go/tools/cache" | ||
| "k8s.io/client-go/util/workqueue" | ||
| ) | ||
|
|
||
| type SecretManager struct { | ||
| Err error | ||
| Secret *corev1.Secret | ||
| IsRegistered bool | ||
| } | ||
|
|
||
| func (m *SecretManager) RegisterRoute(ctx context.Context, namespace string, routeName string, secretName string, handler cache.ResourceEventHandlerFuncs) error { | ||
| return m.Err | ||
| } | ||
| func (m *SecretManager) UnregisterRoute(namespace string, routeName string) error { | ||
| return m.Err | ||
| } | ||
|
|
||
| func (m *SecretManager) GetSecret(ctx context.Context, namespace string, routeName string) (*corev1.Secret, error) { | ||
| return m.Secret, m.Err | ||
| } | ||
| func (m *SecretManager) IsRouteRegistered(namespace string, routeName string) bool { | ||
| return m.IsRegistered | ||
| } | ||
|
|
||
| func (m *SecretManager) Queue() workqueue.RateLimitingInterface { | ||
| return nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| package secretmanager | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "sync" | ||
|
|
||
| "github.com/openshift/library-go/pkg/secret" | ||
| v1 "k8s.io/api/core/v1" | ||
| "k8s.io/client-go/kubernetes" | ||
| "k8s.io/client-go/tools/cache" | ||
| "k8s.io/client-go/util/workqueue" | ||
| "k8s.io/klog/v2" | ||
| ) | ||
|
|
||
| type SecretManager interface { | ||
| RegisterRoute(ctx context.Context, namespace string, routeName string, secretName string, handler cache.ResourceEventHandlerFuncs) error | ||
| UnregisterRoute(namespace string, routeName string) error | ||
| GetSecret(ctx context.Context, namespace string, routeName string) (*v1.Secret, error) | ||
| IsRouteRegistered(namespace string, routeName string) bool | ||
| Queue() workqueue.RateLimitingInterface | ||
| } | ||
|
|
||
| // Manager is responsible for managing secrets associated with routes. It implements SecretManager. | ||
| type manager struct { | ||
| // monitor for managing and watching "single" secret dynamically. | ||
| monitor secret.SecretMonitor | ||
|
|
||
| // Map of registered handlers for each route. | ||
| // Populated inside RegisterRoute() and used in UnregisterRoute(), GetSecret. | ||
| // generateKey() will create the map key. | ||
| registeredHandlers map[string]secret.SecretEventHandlerRegistration | ||
|
|
||
| // Lock to protect access to registeredHandlers map. | ||
| handlersLock sync.RWMutex | ||
|
|
||
| // Work queue to be used by the consumer of this Manager, mostly to add secret change events. | ||
| queue workqueue.RateLimitingInterface | ||
| } | ||
|
|
||
| func NewManager(kubeClient kubernetes.Interface, queue workqueue.RateLimitingInterface) SecretManager { | ||
| return &manager{ | ||
| monitor: secret.NewSecretMonitor(kubeClient), | ||
| handlersLock: sync.RWMutex{}, | ||
| queue: queue, | ||
| registeredHandlers: make(map[string]secret.SecretEventHandlerRegistration), | ||
| } | ||
| } | ||
|
|
||
| // Queue returns the work queue for the manager. | ||
| func (m *manager) Queue() workqueue.RateLimitingInterface { | ||
| return m.queue | ||
| } | ||
|
|
||
| // RegisterRoute registers a route with a secret, enabling the manager to watch for the secret changes and associate them with the handler functions. | ||
| // Returns an error if the route is already registered with a secret or if adding the secret event handler fails. | ||
| func (m *manager) RegisterRoute(ctx context.Context, namespace, routeName, secretName string, handler cache.ResourceEventHandlerFuncs) error { | ||
| m.handlersLock.Lock() | ||
| defer m.handlersLock.Unlock() | ||
|
|
||
| // Generate a unique key for the provided namespace and routeName. | ||
| key := generateKey(namespace, routeName) | ||
|
|
||
| // Check if the route is already registered with the given key. | ||
| // Each route (namespace/routeName) should be registered only once with any secret. | ||
| // Note: inside a namespace multiple different routes can be registered(watch) with a common secret. | ||
| if _, exists := m.registeredHandlers[key]; exists { | ||
| return fmt.Errorf("route already registered with key %s", key) | ||
| } | ||
|
|
||
| // Add a secret event handler for the specified namespace and secret, with the handler functions. | ||
| klog.V(5).Infof("trying to add handler for key %s with secret %s", key, secretName) | ||
| handlerRegistration, err := m.monitor.AddSecretEventHandler(ctx, namespace, secretName, handler) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Store the registration in the manager's map. Used during UnregisterRoute() and GetSecret(). | ||
| m.registeredHandlers[key] = handlerRegistration | ||
| klog.Infof("secret manager registered route for key %s with secret %s", key, secretName) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // UnregisterRoute removes the registration of a route from the manager. | ||
| // It removes the secret event handler from secret monitor and deletes its associated handler from manager's map. | ||
| func (m *manager) UnregisterRoute(namespace, routeName string) error { | ||
| m.handlersLock.Lock() | ||
| defer m.handlersLock.Unlock() | ||
|
|
||
| key := generateKey(namespace, routeName) | ||
|
|
||
| // Get the registered handler. | ||
| handlerRegistration, exists := m.registeredHandlers[key] | ||
| if !exists { | ||
| return fmt.Errorf("no handler registered with key %s", key) | ||
| } | ||
|
|
||
| // Remove the corresponding secret event handler from the secret monitor. | ||
| klog.V(5).Info("trying to remove handler with key", key) | ||
| err := m.monitor.RemoveSecretEventHandler(handlerRegistration) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // delete the registered handler from manager's map of handlers. | ||
| delete(m.registeredHandlers, key) | ||
| klog.Infof("secret manager unregistered route for key %s", key) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // GetSecret retrieves the secret object registered with a route. | ||
| func (m *manager) GetSecret(ctx context.Context, namespace, routeName string) (*v1.Secret, error) { | ||
| m.handlersLock.RLock() | ||
| defer m.handlersLock.RUnlock() | ||
|
|
||
| key := generateKey(namespace, routeName) | ||
|
|
||
| handlerRegistration, exists := m.registeredHandlers[key] | ||
| if !exists { | ||
| return nil, fmt.Errorf("no handler registered with key %s", key) | ||
| } | ||
|
|
||
| // Get the secret from the secret monitor's cache using the registered handler. | ||
| obj, err := m.monitor.GetSecret(ctx, handlerRegistration) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return obj, nil | ||
| } | ||
|
|
||
| // IsRouteRegistered returns true if route is registered, false otherwise | ||
| func (m *manager) IsRouteRegistered(namespace, routeName string) bool { | ||
| m.handlersLock.RLock() | ||
| defer m.handlersLock.RUnlock() | ||
|
|
||
| key := generateKey(namespace, routeName) | ||
chiragkyal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| _, exists := m.registeredHandlers[key] | ||
| return exists | ||
| } | ||
|
|
||
| // generateKey creates a unique identifier for a route | ||
| func generateKey(namespace, route string) string { | ||
| return fmt.Sprintf("%s/%s", namespace, route) | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.