mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 20:28:16 +00:00
fix: changes
This commit is contained in:
@@ -7,14 +7,11 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||||
|
|
||||||
defaultErrors "errors"
|
defaultErrors "errors"
|
||||||
@@ -62,6 +59,8 @@ func (r *InfisicalSecretReconciler) GetLogger(req ctrl.Request) logr.Logger {
|
|||||||
func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
logger := r.GetLogger(req)
|
logger := r.GetLogger(req)
|
||||||
|
|
||||||
|
logger.Info("Reconcile called")
|
||||||
|
|
||||||
var infisicalSecretCRD secretsv1alpha1.InfisicalSecret
|
var infisicalSecretCRD secretsv1alpha1.InfisicalSecret
|
||||||
requeueTime := time.Minute // seconds
|
requeueTime := time.Minute // seconds
|
||||||
|
|
||||||
@@ -181,8 +180,8 @@ func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
if infisicalSecretCRD.Spec.InstantUpdates {
|
if infisicalSecretCRD.Spec.InstantUpdates {
|
||||||
logger.Info("Event watcher enabled")
|
logger.Info("Instant updates are enabled")
|
||||||
// ensure event watcher is open
|
|
||||||
if err := r.EnsureEventStream(ctx, logger, &infisicalSecretCRD); err != nil {
|
if err := r.EnsureEventStream(ctx, logger, &infisicalSecretCRD); err != nil {
|
||||||
logger.Error(err, fmt.Sprintf("unable to ensure event stream. Will requeue after [requeueTime=%v]", requeueTime))
|
logger.Error(err, fmt.Sprintf("unable to ensure event stream. Will requeue after [requeueTime=%v]", requeueTime))
|
||||||
return ctrl.Result{
|
return ctrl.Result{
|
||||||
@@ -190,7 +189,6 @@ func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ensure event stream is closed
|
|
||||||
r.CloseEventStream(ctx, logger, &infisicalSecretCRD)
|
r.CloseEventStream(ctx, logger, &infisicalSecretCRD)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,15 +205,10 @@ func (r *InfisicalSecretReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|||||||
return ctrl.NewControllerManagedBy(mgr).
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
Watches(
|
Watches(
|
||||||
&source.Channel{Source: r.SourceCh},
|
&source.Channel{Source: r.SourceCh},
|
||||||
handler.EnqueueRequestsFromMapFunc(r.findSecretsForCluster),
|
&util.EnqueueDelayedEventHandler{Delay: time.Second * 3},
|
||||||
).
|
).
|
||||||
For(&secretsv1alpha1.InfisicalSecret{}, builder.WithPredicates(predicate.Funcs{
|
For(&secretsv1alpha1.InfisicalSecret{}, builder.WithPredicates(predicate.Funcs{
|
||||||
GenericFunc: func(ge event.GenericEvent) bool {
|
|
||||||
fmt.Println("Generic event recieved")
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
UpdateFunc: func(e event.UpdateEvent) bool {
|
UpdateFunc: func(e event.UpdateEvent) bool {
|
||||||
println("UpdateFunc event recieved")
|
|
||||||
if e.ObjectOld.GetGeneration() == e.ObjectNew.GetGeneration() {
|
if e.ObjectOld.GetGeneration() == e.ObjectNew.GetGeneration() {
|
||||||
return false // Skip reconciliation for status-only changes
|
return false // Skip reconciliation for status-only changes
|
||||||
}
|
}
|
||||||
@@ -241,31 +234,3 @@ func (r *InfisicalSecretReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|||||||
Complete(r)
|
Complete(r)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *InfisicalSecretReconciler) findSecretsForCluster(o client.Object) []reconcile.Request {
|
|
||||||
ctx := context.Background()
|
|
||||||
secrets := &secretsv1alpha1.InfisicalSecretList{}
|
|
||||||
|
|
||||||
requests := []reconcile.Request{}
|
|
||||||
|
|
||||||
if err := r.List(ctx, secrets); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return requests
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sec := range secrets.Items {
|
|
||||||
if sec.GetName() == o.GetName() && sec.GetNamespace() == o.GetNamespace() {
|
|
||||||
requests = append(requests, reconcile.Request{
|
|
||||||
NamespacedName: types.NamespacedName{
|
|
||||||
Namespace: o.GetNamespace(),
|
|
||||||
Name: o.GetName(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(requests)
|
|
||||||
|
|
||||||
return requests
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -469,7 +469,7 @@ func (r *InfisicalSecretReconciler) getResourceVariables(infisicalSecret v1alpha
|
|||||||
InfisicalClient: client,
|
InfisicalClient: client,
|
||||||
CancelCtx: cancel,
|
CancelCtx: cancel,
|
||||||
AuthDetails: util.AuthenticationDetails{},
|
AuthDetails: util.AuthenticationDetails{},
|
||||||
ServerSentEvents: sse.NewConnectionRegistry(),
|
ServerSentEvents: sse.NewConnectionRegistry(ctx),
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceVariables = infisicalSecretResourceVariablesMap[string(infisicalSecret.UID)]
|
resourceVariables = infisicalSecretResourceVariablesMap[string(infisicalSecret.UID)]
|
||||||
@@ -509,7 +509,7 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
|
|||||||
InfisicalClient: infisicalClient,
|
InfisicalClient: infisicalClient,
|
||||||
CancelCtx: cancelCtx,
|
CancelCtx: cancelCtx,
|
||||||
AuthDetails: authDetails,
|
AuthDetails: authDetails,
|
||||||
ServerSentEvents: sse.NewConnectionRegistry(),
|
ServerSentEvents: sse.NewConnectionRegistry(ctx),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,41 +638,43 @@ func (r *InfisicalSecretReconciler) EnsureEventStream(ctx context.Context, logge
|
|||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/v1/events/subscribe/project-events", api.API_HOST_URL), strings.NewReader(string(body)))
|
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/v1/events/subscribe/project-events", api.API_HOST_URL), strings.NewReader(string(body)))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
for k, v := range headers {
|
for k, v := range headers {
|
||||||
req.Header.Set(k, v)
|
req.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, err
|
return req, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to connect to SSE server [err=%s]", err)
|
return fmt.Errorf("unable to connect to SSE server [err=%s]", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
outer:
|
go func() {
|
||||||
for {
|
outer:
|
||||||
select {
|
for {
|
||||||
case ev := <-events:
|
select {
|
||||||
logger.Info("Received event", "secret", secret, "event", ev)
|
case ev := <-events:
|
||||||
r.SourceCh <- event.GenericEvent{
|
logger.Info("Received SSE Event", "event", ev)
|
||||||
Object: secret,
|
r.SourceCh <- event.GenericEvent{
|
||||||
|
Object: secret,
|
||||||
|
}
|
||||||
|
case err := <-errors:
|
||||||
|
logger.Error(err, "Error occurred")
|
||||||
|
break outer
|
||||||
|
case <-ctx.Done():
|
||||||
|
break outer
|
||||||
}
|
}
|
||||||
logger.Info("Send to channel")
|
|
||||||
case err := <-errors:
|
|
||||||
logger.Error(err, "Error occurred")
|
|
||||||
break outer
|
|
||||||
case <-ctx.Done():
|
|
||||||
logger.Info("Context done")
|
|
||||||
break outer
|
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *InfisicalSecretReconciler) CloseEventStream(ctx context.Context, logger logr.Logger, secret *secretsv1alpha1.InfisicalSecret) error {
|
func (r *InfisicalSecretReconciler) CloseEventStream(ctx context.Context, logger logr.Logger, secret *secretsv1alpha1.InfisicalSecret) error {
|
||||||
logger.Info("Event watcher disabled")
|
|
||||||
|
|
||||||
if secret == nil {
|
if secret == nil {
|
||||||
return fmt.Errorf("infisicalSecret is nil")
|
return fmt.Errorf("infisicalSecret is nil")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -37,7 +36,6 @@ func (e *EnqueueDelayedEventHandler) Delete(_ event.DeleteEvent, _ workqueue.Rat
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *EnqueueDelayedEventHandler) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
func (e *EnqueueDelayedEventHandler) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||||
fmt.Println(evt)
|
|
||||||
if evt.Object == nil {
|
if evt.Object == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,5 +11,5 @@ type ResourceVariables struct {
|
|||||||
InfisicalClient infisicalSdk.InfisicalClientInterface
|
InfisicalClient infisicalSdk.InfisicalClientInterface
|
||||||
CancelCtx context.CancelFunc
|
CancelCtx context.CancelFunc
|
||||||
AuthDetails AuthenticationDetails
|
AuthDetails AuthenticationDetails
|
||||||
ServerSentEvents sse.ConnectionRegistry
|
ServerSentEvents *sse.ConnectionRegistry
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,134 +4,162 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConnectionMeta holds metadata about an active SSE connection
|
|
||||||
type ConnectionMeta struct {
|
type ConnectionMeta struct {
|
||||||
EventChan <-chan SSEEvent
|
EventChan <-chan SSEEvent
|
||||||
ErrorChan <-chan error
|
ErrorChan <-chan error
|
||||||
Cancel context.CancelFunc
|
|
||||||
LastPingAt time.Time
|
LastPingAt time.Time
|
||||||
|
Cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectionRegistry manages a single SSE connection with a shared client
|
|
||||||
type ConnectionRegistry struct {
|
type ConnectionRegistry struct {
|
||||||
Ticker *time.Ticker
|
Ctx context.Context
|
||||||
meta *ConnectionMeta
|
meta *ConnectionMeta
|
||||||
client SSEClient
|
client SSEClient
|
||||||
|
mu sync.RWMutex
|
||||||
|
|
||||||
|
monitorCancel context.CancelFunc
|
||||||
|
monitorCtx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConnectionRegistry creates a new registry
|
func NewConnectionRegistry(ctx context.Context) *ConnectionRegistry {
|
||||||
func NewConnectionRegistry() ConnectionRegistry {
|
monitorCtx, monitorCancel := context.WithCancel(ctx)
|
||||||
return ConnectionRegistry{
|
return &ConnectionRegistry{
|
||||||
Ticker: time.NewTicker(time.Second * 30),
|
Ctx: ctx,
|
||||||
client: NewClient(),
|
client: NewClient(),
|
||||||
|
monitorCtx: monitorCtx,
|
||||||
|
monitorCancel: monitorCancel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrCreate returns existing connection or creates a new one
|
// create creates a new connection
|
||||||
func (r *ConnectionRegistry) GetOrCreate(
|
func (r *ConnectionRegistry) create(req *http.Request) (*ConnectionMeta, error) {
|
||||||
onBuild func() (*http.Request, error),
|
// Create new connection using provided request
|
||||||
) (*ConnectionMeta, error) {
|
|
||||||
// First try to get existing connection
|
|
||||||
if r.meta != nil {
|
|
||||||
return r.meta, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new connection
|
|
||||||
req, err := onBuild()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to build request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add cancellation context
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
|
|
||||||
eventChan, errorChan, err := r.client.Connect(req)
|
eventChan, errorChan, err := r.client.Connect(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel()
|
|
||||||
return nil, fmt.Errorf("failed to connect: %w", err)
|
return nil, fmt.Errorf("failed to connect: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
meta := &ConnectionMeta{
|
meta := &ConnectionMeta{
|
||||||
EventChan: eventChan,
|
EventChan: eventChan,
|
||||||
ErrorChan: errorChan,
|
ErrorChan: errorChan,
|
||||||
Cancel: cancel,
|
|
||||||
LastPingAt: time.Now(),
|
LastPingAt: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
r.meta = meta
|
r.meta = meta
|
||||||
|
|
||||||
// Start cleanup monitor for this connection
|
// Start cleanup monitor for this connection (NON-BLOCKING)
|
||||||
go r.monitor(ctx, meta)
|
go r.monitor(meta)
|
||||||
|
|
||||||
|
println("Creating new connection\n")
|
||||||
return meta, nil
|
return meta, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get retrieves the existing connection
|
// Get retrieves the existing connection
|
||||||
func (r *ConnectionRegistry) Get() (*ConnectionMeta, bool) {
|
func (r *ConnectionRegistry) Get() (*ConnectionMeta, bool) {
|
||||||
|
r.mu.RLock()
|
||||||
|
defer r.mu.RUnlock()
|
||||||
return r.meta, r.meta != nil
|
return r.meta, r.meta != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the connection
|
// Close closes the connection
|
||||||
func (r *ConnectionRegistry) Close() {
|
func (r *ConnectionRegistry) Close() {
|
||||||
|
r.mu.Lock()
|
||||||
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
if r.meta != nil {
|
if r.meta != nil {
|
||||||
r.meta.Cancel()
|
if r.meta.Cancel != nil {
|
||||||
|
r.meta.Cancel()
|
||||||
|
}
|
||||||
r.meta = nil
|
r.meta = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel the monitor
|
||||||
|
if r.monitorCancel != nil {
|
||||||
|
r.monitorCancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsConnected returns whether there's an active connection
|
// IsConnected returns whether there's an active connection
|
||||||
func (r *ConnectionRegistry) IsConnected() bool {
|
func (r *ConnectionRegistry) IsConnected() bool {
|
||||||
|
r.mu.RLock()
|
||||||
|
defer r.mu.RUnlock()
|
||||||
return r.meta != nil
|
return r.meta != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// monitorConnection watches for connection closure and cleans up
|
// UpdateLastPing updates the last ping time
|
||||||
func (r *ConnectionRegistry) monitor(ctx context.Context, meta *ConnectionMeta) {
|
func (r *ConnectionRegistry) UpdateLastPing() {
|
||||||
outer:
|
r.mu.Lock()
|
||||||
for range r.Ticker.C {
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
|
if r.meta != nil {
|
||||||
|
r.meta.LastPingAt = time.Now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// monitor watches for connection closure and cleans up
|
||||||
|
func (r *ConnectionRegistry) monitor(meta *ConnectionMeta) {
|
||||||
|
ticker := time.NewTicker(30 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-r.monitorCtx.Done():
|
||||||
break outer
|
// Context cancelled, exit monitor
|
||||||
default:
|
return
|
||||||
if r.IsConnected() && time.Since(r.meta.LastPingAt) > 2*time.Minute {
|
|
||||||
fmt.Println("Last ping was more than 2 minutes ago")
|
case <-ticker.C:
|
||||||
r.Close()
|
r.mu.RLock()
|
||||||
break outer
|
currentMeta := r.meta
|
||||||
} else {
|
r.mu.RUnlock()
|
||||||
fmt.Println("Last ping was within the last 2 minutes")
|
|
||||||
|
// Check if this monitor is still relevant
|
||||||
|
if currentMeta != meta {
|
||||||
|
// This connection has been replaced, exit monitor
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentMeta != nil && time.Since(currentMeta.LastPingAt) > 2*time.Minute {
|
||||||
|
fmt.Println("Last ping was more than 2 minutes ago, closing connection")
|
||||||
|
r.mu.Lock()
|
||||||
|
if r.meta == meta { // Double-check under lock
|
||||||
|
if r.meta.Cancel != nil {
|
||||||
|
r.meta.Cancel()
|
||||||
|
}
|
||||||
|
r.meta = nil
|
||||||
|
}
|
||||||
|
r.mu.Unlock()
|
||||||
|
return // Exit monitor after cleanup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up from registry
|
|
||||||
if r.meta == meta {
|
|
||||||
r.meta = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConnectionInfo provides read-only info about a connection
|
|
||||||
type ConnectionInfo struct {
|
|
||||||
LastPingAt time.Time
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe provides a convenient way to get events from the connection
|
// Subscribe provides a convenient way to get events from the connection
|
||||||
func (r *ConnectionRegistry) Subscribe(
|
func (r *ConnectionRegistry) Subscribe(build func() (*http.Request, error)) (<-chan SSEEvent, <-chan error, error) {
|
||||||
onBuild func() (*http.Request, error),
|
r.mu.Lock()
|
||||||
) (<-chan SSEEvent, <-chan error, error) {
|
defer r.mu.Unlock()
|
||||||
meta, err := r.GetOrCreate(onBuild)
|
|
||||||
|
// Get existing connection if available
|
||||||
|
if r.meta != nil {
|
||||||
|
return r.meta.EventChan, r.meta.ErrorChan, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := build()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new connection if none exists
|
||||||
|
meta, err := r.create(req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return meta.EventChan, meta.ErrorChan, nil
|
return meta.EventChan, meta.ErrorChan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconnect closes existing connection and creates a new one
|
|
||||||
func (r *ConnectionRegistry) Reconnect(
|
|
||||||
onBuild func() (*http.Request, error),
|
|
||||||
) (*ConnectionMeta, error) {
|
|
||||||
r.Close()
|
|
||||||
return r.GetOrCreate(onBuild)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user