# Watching secondary resources that are NOT `Owned`

In some scenarios, a controller may need to watch and respond to changes in
resources that it does not `Own`, meaning those resources are created and managed by
another controller.

The following examples demonstrate how a controller can monitor and reconcile resources
that it doesn’t directly manage. This applies to any resource not `Owned` by the controller,
including **Core Types** or **Custom Resources** managed by other controllers or projects
and reconciled in separate processes.

For instance, consider two custom resources—`Busybox` and `BackupBusybox`.
If changes to `Busybox` should trigger reconciliation in the `BackupBusybox` controller,
configure the `BackupBusybox` controller to watch for updates in `Busybox`.

### Example: Watching a Non-Owned Busybox Resource to Reconcile BackupBusybox

Consider a controller that manages a custom resource `BackupBusybox`
but also needs to monitor changes to `Busybox` resources across the cluster.
Trigger reconciliation only when `Busybox` instances have the Backup
feature enabled.

- **Why Watch Secondary Resources?**
    - The `BackupBusybox` controller is not responsible for creating or owning `Busybox`
    resources, but changes in these resources (such as updates or deletions) directly affect the primary
    resource (`BackupBusybox`).
    - By watching `Busybox` instances with a specific label, the controller ensures that the necessary
    actions (e.g., backups) are triggered only for the relevant resources.

### Configuration example

Here’s how to configure the `BackupBusyboxReconciler` to watch changes in the
`Busybox` resource and trigger reconciliation for `BackupBusybox`:

```go
// SetupWithManager sets up the controller with the Manager.
// The controller watches both the BackupBusybox primary resource and the Busybox resource.
func (r *BackupBusyboxReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&examplecomv1alpha1.BackupBusybox{}).  // Watch the primary resource (BackupBusybox)
        Watches(
            &examplecomv1alpha1.Busybox{},  // Watch the Busybox CR
            handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
                // Trigger reconciliation for the BackupBusybox in the same namespace
                return []reconcile.Request{
                    {
                        NamespacedName: types.NamespacedName{
                            Name:      "backupbusybox",  // Reconcile the associated BackupBusybox resource
                            Namespace: obj.GetNamespace(),  // Use the namespace of the changed Busybox
                        },
                    },
                }
            }),
        ).  // Trigger reconciliation when the Busybox resource changes
        Complete(r)
}
```

Here’s how to configure the controller to filter and watch
for changes to only those `Busybox` resources that have the specific label:

```go
// SetupWithManager sets up the controller with the Manager.
// The controller watches both the BackupBusybox primary resource and the Busybox resource, filtering by a label.
func (r *BackupBusyboxReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&examplecomv1alpha1.BackupBusybox{}).  // Watch the primary resource (BackupBusybox)
        Watches(
            &examplecomv1alpha1.Busybox{},  // Watch the Busybox CR
            handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
                // Check if the Busybox resource has the label 'backup-needed: "true"'
                if val, ok := obj.GetLabels()["backup-enable"]; ok && val == "true" {
                    // If the label is present and set to "true", trigger reconciliation for BackupBusybox
                    return []reconcile.Request{
                        {
                            NamespacedName: types.NamespacedName{
                                Name:      "backupbusybox",  // Reconcile the associated BackupBusybox resource
                                Namespace: obj.GetNamespace(),  // Use the namespace of the changed Busybox
                            },
                        },
                    }
                }
                // If the label is not present or does not match, do not trigger reconciliation
                return []reconcile.Request{}
            }),
        ).  // Trigger reconciliation when the labeled Busybox resource changes
        Complete(r)
}
```
