Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions infra/feast-operator/docs/namespace-registry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Feast Namespace Registry

## Overview

The Feast Namespace Registry is a feature that automatically creates and maintains a centralized ConfigMap containing information about all Feast feature store instances deployed by the operator. This enables dashboard applications and other tools to discover and connect to Feast instances across different namespaces.

## Implementation Details

1. **ConfigMap Creation**: The operator creates a ConfigMap in the appropriate namespace:
- **OpenShift AI**: `redhat-ods-applications` namespace (or DSCi configured namespace)
- **Kubernetes**: `feast-operator-system` namespace

2. **Access Control**: A RoleBinding is created to allow `system:authenticated` users to read the ConfigMap

3. **Automatic Registration & Cleanup**: When a new feature store instance is created, it automatically registers its namespace and client configuration in the ConfigMap. When deleted, it automatically removes its entry from the ConfigMap

4. **Data Structure**: The ConfigMap contains a JSON structure with namespace names as keys and lists of client configuration names as values

### ConfigMap Structure

The namespace registry ConfigMap (`feast-configs-registry`) contains the following data:

```json
{
"namespaces": {
"namespace-1": ["client-config-1", "client-config-2"],
"namespace-2": ["client-config-3"]
}
}
```

### Usage

The namespace registry is automatically deployed when any Feast feature store instance is created. No additional configuration is required.

#### For External Applications

External applications can discover Feast instances by:

1. Reading the ConfigMap from the appropriate namespace:
```bash
# For OpenShift
kubectl get configmap feast-configs-registry -n redhat-ods-applications -o jsonpath='{.data.namespaces}'

# For Kubernetes
kubectl get configmap feast-configs-registry -n feast-operator-system -o jsonpath='{.data.namespaces}'
```

### Lifecycle Management

The namespace registry automatically manages the lifecycle of feature store instances:

1. **Creation**: When a feature store is deployed, it registers itself in the ConfigMap
2. **Updates**: If a feature store is updated, its entry remains in the ConfigMap
3. **Deletion**: When a feature store is deleted, its entry is automatically removed from the ConfigMap
4. **Namespace Cleanup**: If all feature stores in a namespace are deleted, the namespace entry is also removed


Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ func (r *FeatureStoreReconciler) Reconcile(ctx context.Context, req ctrl.Request
if apierrors.IsNotFound(err) {
// CR deleted since request queued, child objects getting GC'd, no requeue
logger.V(1).Info("FeatureStore CR not found, has been deleted")
// Clean up namespace registry entry even if the CR is not found
if err := r.cleanupNamespaceRegistry(ctx, &feastdevv1alpha1.FeatureStore{
ObjectMeta: metav1.ObjectMeta{
Name: req.NamespacedName.Name,
Namespace: req.NamespacedName.Namespace,
},
}); err != nil {
logger.Error(err, "Failed to clean up namespace registry entry for deleted FeatureStore")
// Don't return error here as the CR is already deleted
}
return ctrl.Result{}, nil
}
// error fetching FeatureStore instance, requeue and try again
Expand All @@ -86,6 +96,16 @@ func (r *FeatureStoreReconciler) Reconcile(ctx context.Context, req ctrl.Request
}
currentStatus := cr.Status.DeepCopy()

// Handle deletion - clean up namespace registry entry
if cr.DeletionTimestamp != nil {
logger.Info("FeatureStore is being deleted, cleaning up namespace registry entry")
if err := r.cleanupNamespaceRegistry(ctx, cr); err != nil {
logger.Error(err, "Failed to clean up namespace registry entry")
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}

result, recErr = r.deployFeast(ctx, cr)
if cr.DeletionTimestamp == nil && !reflect.DeepEqual(currentStatus, cr.Status) {
if err = r.Client.Status().Update(ctx, cr); err != nil {
Expand All @@ -102,6 +122,22 @@ func (r *FeatureStoreReconciler) Reconcile(ctx context.Context, req ctrl.Request
}
}

// Add to namespace registry if deployment was successful and not being deleted
if recErr == nil && cr.DeletionTimestamp == nil {
feast := services.FeastServices{
Handler: feasthandler.FeastHandler{
Client: r.Client,
Context: ctx,
FeatureStore: cr,
Scheme: r.Scheme,
},
}
if err := feast.AddToNamespaceRegistry(); err != nil {
logger.Error(err, "Failed to add FeatureStore to namespace registry")
// Don't return error here as the FeatureStore is already deployed successfully
}
}

return result, recErr
}

Expand Down Expand Up @@ -201,6 +237,20 @@ func (r *FeatureStoreReconciler) SetupWithManager(mgr ctrl.Manager) error {

}

// cleanupNamespaceRegistry removes the feature store instance from the namespace registry
func (r *FeatureStoreReconciler) cleanupNamespaceRegistry(ctx context.Context, cr *feastdevv1alpha1.FeatureStore) error {
feast := services.FeastServices{
Handler: feasthandler.FeastHandler{
Client: r.Client,
Context: ctx,
FeatureStore: cr,
Scheme: r.Scheme,
},
}

return feast.RemoveFromNamespaceRegistry()
}

// if a remotely referenced FeatureStore is changed, reconcile any FeatureStores that reference it.
func (r *FeatureStoreReconciler) mapFeastRefsToFeastRequests(ctx context.Context, object client.Object) []reconcile.Request {
logger := log.FromContext(ctx)
Expand Down
Loading
Loading