Skip to content
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

Add support for template-based label/annotation matching #193

Open
tamoreton opened this issue Oct 27, 2024 · 4 comments
Open

Add support for template-based label/annotation matching #193

tamoreton opened this issue Oct 27, 2024 · 4 comments

Comments

@tamoreton
Copy link

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:

  1. Evaluate the template expressions against the namespace
  2. 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

  1. Using standard label selectors with Exists operator - less precise, can't validate naming convention
  2. Using separate trigger labels - works but adds unnecessary complexity
  3. 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.

@raffaelespazzoli
Copy link
Collaborator

your alternative #1 would be my recommendation for this use case. Can you explain in which sense it is less precise?

@tamoreton
Copy link
Author

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).

@raffaelespazzoli
Copy link
Collaborator

I am not sure I fully understand the use case. But it looks like you need to be able to do two things:

  1. discriminate between tenant and system namespaces
  2. 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.

@tamoreton
Copy link
Author

tamoreton commented Nov 6, 2024

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:

  1. 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 put argocd.argoproj.io/managed-by: <namespace-name>-argo on the namespace or I assume it wouldn't work correctly in difficult-to-reason-about ways.

  2. 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.

  3. Require both of the above. So you need to have myplatform.com/tenant-gitops: "true" and argocd.argoproj.io/managed-by on the namespace to get the NamespaceConfig; 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 NamespaceConfigs 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 🧐

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants