Add support for template-based label/annotation matching
Opened this issue · 4 comments
Use case
When creating namespace configurations, there are scenarios where we want to match labels/annotations based on dynamic values derived from the namespace itself.
For example, a common pattern is to have ArgoCD instances managing namespaces where the instance name is derived from the namespace name:
metadata:
name: my-project
labels:
argocd.argoproj.io/managed-by: my-project-argo
Currently, we can't create a NamespaceConfig that matches based on this pattern without requiring additional trigger labels.
Proposed solution
Add a new field to the NamespaceConfig spec for template-based matching:
apiVersion: redhatcop.redhat.io/v1alpha1
kind: NamespaceConfig
metadata:
name: gitops-config
spec:
labelMatchTemplate:
argocd.argoproj.io/managed-by: "{{ .Name }}-argo"
templates:
- objectTemplate: |
apiVersion: v1
kind: Namespace
metadata:
name: {{ .Name }}-argo
This would allow the operator to:
- Evaluate the template expressions against the namespace
- Check if the resulting key-value pairs match the namespace's actual labels/annotations
Benefits
- More intuitive configurations that can use self-referential patterns
- Reduction in redundant labeling (no need for separate trigger labels)
- Better support for common patterns like ArgoCD management where instance names follow a convention
- More maintainable configurations as relationships are more explicit
Alternatives considered
- Using standard label selectors with
Exists
operator - less precise, can't validate naming convention - Using separate trigger labels - works but adds unnecessary complexity
- Using regexp matching - possible but less intuitive and harder to maintain
Would this feature be valuable to the project? Happy to provide more details or discuss alternative approaches.
your alternative #1 would be my recommendation for this use case. Can you explain in which sense it is less precise?
If I just check that a label with the key argocd.argoproj.io/managed-by
exists, then the NamespaceConfig may unintentionally be applied to non-tenant namespaces. So then we need to have some additional selector, e.g. myplatform.com/tenant-gitops-namespace: tenant-app-argo
, but then a team has to have both selectors on their namespace, and they need to match each other (and argocd.argoproj.io/managed-by
will refer to a namespace that does not yet exist).
I am not sure I fully understand the use case. But it looks like you need to be able to do two things:
- discriminate between tenant and system namespaces
- for tenant namespaces, apply a namespace config.
It also seems like you are trying to discriminate between tenant and system namespace with a label argocd.argoproj.io/managed-by
that does not really contain that information as you use it for both tenant and non-tenant namespaces. Assuming you have a good reason for doping that (as opposed to simply add another label: tenant: "true"
, for example), then you'll need to have either whitelist (of tenant namespaces) or a blacklist (of system namespaces). With the list information you can add a second selector that actually matches only the namespaces you want.
Finally I don't understand your initial example: you cannot create namespaces in a namespace config. You are supposed to create manifests within the matched (and pre-existing) namespaces.
The use case is a platform-as-a-service where each tenant gets their own Argo CD server. The Argo CD server is in its own namespace so that it doesn't use the same resource quota as the resources in the namespace itself, and also because teams may want to be able to configure separate access control for deployment and development. So it's not that we're using the namespace configuration operator to create the namespace, it's that we're using it to create an additional, companion namespace.
For realising this with selectors I tried these options:
-
Have
myplatform.com/tenant-gitops: "true"
as the required label. This would automatically generate an additional namespace named<namespace-name>-argo
. But you'd also have to remember to putargocd.argoproj.io/managed-by: <namespace-name>-argo
on the namespace or I assume it wouldn't work correctly in difficult-to-reason-about ways. -
Have
argocd.argoproj.io/managed-by
as the required label key, and use its value to generate the name of the Argo CD namespace—so then any Argo CD-managed namespace gets configured in this way. But using a selector which is a label that is defined by a different operator this might inadvertently target namespaces which aren't tenant namespaces. -
Require both of the above. So you need to have
myplatform.com/tenant-gitops: "true"
andargocd.argoproj.io/managed-by
on the namespace to get theNamespaceConfig
; i.e.spec: labelSelector: matchExpressions: - key: argocd.argoproj.io/managed-by operator: Exists matchLabels: myplatform.com/tenant-gitops: "true"
This proposal is essentially to create an option 4, to be able to do this with a single label.
I went with option 3 for now, but the NamespaceConfig
resource in Argo CD had an error on it like, "the object has been modified; please apply your changes to the latest version and try again" (other NamespaceConfig
s were fine), and when trying to force sync the resource, it actually deleted all the resources in the openshift-gitops namespace and the openshift-gitops namespace itself got stuck in a Terminating
state. So I think deleting this NamespaceConfig
somehow caused openshift-gitops to delete itself 🧐