kubernetes-sigs / kustomize

Customization of kubernetes YAML configurations
Apache License 2.0
11.09k stars 2.26k forks source link

Use labels to filter `source` in `replacements` #4763

Open davinkevin opened 2 years ago

davinkevin commented 2 years ago

Is your feature request related to a problem? Please describe.

As a kustomize & Sealed Secrets user, I would like to use replacement to populate the field spec.tls.0.secretName of an Ingress.

The problem is I don't know beforehand the secret name, but only labels. And obviously, I have multiple SealedSecrets in my setup (some for applications, some for certificates…).

replacements:
  - source:
      kind: SealedSecret
      name: "I don't know the name…"
    targets:
      - select:
          kind: Ingress
        fieldPaths:
          - spec.tls.0.secretName
        options:
          create: true

So if I use something like this, the result is an error like this Error: multiple matches for selector SealedSecret.[noVer].[noGrp]/[noName].[noNs], which is expected from the specification

Describe the solution you'd like

I would like to add some more advanced criteria to resolve the object I want in source. In my context, and to be Kubernetes idiomatic, using labels would do the job perfectly. For example, a potential API for that:

replacements:
  - source:
      kind: SealedSecret
      matchLabels:
        app.kubernetes.io/component: certificate
        app.kubernetes.io/env: dev
    targets:
      - select:
          kind: Ingress
        fieldPaths:
          - spec.tls.0.secretName
        options:
          create: true

Describe alternatives you've considered

I don't have any alternative at the moment, so I have to duplicate the name and update the entry in my Ingress definition every time I want to deploy it.

Additional context

No additional context, feel free to ask question if you want. The method to be modified, IIUC is named selectSourceNode

natasha41575 commented 2 years ago

We will accept this request, but the syntax for label and/or annotation selection in the source selector should be identical to the label/annotation selection in targets. Looking through the kustomize code, it looks like target selectors are specified with the fields annotationSelector and labelSelector, which you can see here https://github.com/kubernetes-sigs/kustomize/blob/482e8930fc256672afd4ff5d531ec8fe80d35119/api/types/selector.go#L28.

/triage accepted

davinkevin commented 2 years ago

Thank you 🙏 and really good thing to use this api rather than the Kubernetes one. Being able to use labels and/or annotations is a great idea too.

jamesloosli commented 2 years ago

Is there any documentation or working examples for labelSelector?

I'm trying the following;

base.yaml

---
apiVersion: getambassador.io/v3alpha1
kind: Host
metadata:
  name: api-regional
  labels:
    host-type: regional
spec:
  hostname: "api.nonprod-us-west-2.some.link"
---
apiVersion: getambassador.io/v3alpha1
kind: Host
metadata:
  name: api-apex
  labels:
    host-type: apex
spec:
  hostname: "api.some.link"

kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: some-namespace
replacements:
  - path: ../replacements/tld.yaml

tld.yaml

source: { kind: ConfigMap, name: some-env, fieldPath: data.DOMAIN_SUFFIX }
targets:
  # apex hosts
  - select:
      kind: Host
      labelSelector: host-type=apex
    fieldPaths: [spec.hostname]
    options: { delimiter: ".", index: 2 }

  # regional hosts
  - select:
      kind: Host
      labelSelector: host-type=regional
    fieldPaths: [spec.hostname]
    options: { delimiter: ".", index: 3 }

I feel like there's something basic I'm missing here. I'm using the document here; https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api, to guess at what labelSelector is expecting, but I don't seem to be on track. I get this error;

error unmarshaling JSON: while decoding JSON: json: cannot unmarshal object into Go struct field Selector.targets.select.labelSelector of type string

davinkevin commented 2 years ago

@jamesloosli the proposition is not yet implemented 🤔, I think this is why you have this error.

vugardzhamalov commented 1 year ago

Dear @natasha41575 @davinkevin,

Is this correct to assume that what you are proposing will be somewhat identical to 'labelSelector' and/or 'annotationSelector' already implemented in patch transformer, see here? If so am I correct to assume that these could be implemented both for replacements 'source:' and 'targets[select:]' and 'targets[reject:]'? Thank you!

vugardzhamalov commented 1 year ago

The only thing of course is that originally @davinkevin was talking about the set of labels to match. And current implementation in patch transformer does matching on a single label/annotation. This brings me to another question (I guess I shouldn't even ask here) to @natasha41575 : do you think it will be difficult to replace strings with sets in patch transformer as well? Or to avoid breaking changes... maybe to introduce new sets in addition to existing single label and annotation selectors? Thank you!

davinkevin commented 1 year ago

In my case, only one labelSelector or annotationSelector couldn't be enough. In k8s, we use both with a lot of information to make debug/operation simpler. In this issue context, it could looks like this:

replacements:
  - source:
      kind: SealedSecret
      labelSelector:
        app.kubernetes.io/type: certificate
        app.kubernetes.io/env: dev
        app.kuberentes.io/domain: "*.foo.com"
    targets:
      …

It was really my original request to have multiple filter. Obviously, using a syntax like this one is something possible, but a bit strange for a new API.

vugardzhamalov commented 1 year ago

Awesome find @davinkevin! Thank you!I had no idea! As per the link you've kindly provided earlier: "operations may specify label selectors to filter the sets of objects". Not sure if my interpretation is off here: just had a quick test on patch transformer it seems as if 'labelSelector:' string value could be used for a comma separated object declaration. It seems as if negation (!=) is also supported. Meaning that following works for multiple labels. Interesting find I don't think I've seen it documented anywhere in the Kustomize documentation:

labelSelector: 'key01=val01,key02=val02,key03!=val02'

Had no chance to confirm but I am guessing the same will work with 'annotationSelector:'

It looks as if value based filtering with multiple operators, please see here, is also supported, e.g:

labelSelector: 'key in (val01,val02,val03)'

davinkevin commented 1 year ago

@vugardzhamalov 👍. To be honest, I'm not a huge fan of the string api with query in it (it's good for CLI but not so much for YAML from my point of view), but if it does the job, I'm 100% in!

Thank you for this, I can't wait to see it release 😍

jamesloosli commented 1 year ago

Also anxiously waiting for this to release. Since 5.0.0 throws errors for unmatched replacements, we're unable to use the latest Kustomize.

@jamesloosli the proposition is not yet implemented 🤔, I think this is why you have this error.

Well that makes sense.

vugardzhamalov commented 1 year ago

Dear @natasha41575 @davinkevin,

and 'targets[select:]' and 'targets[reject:]'? Thank you!

Also I've just realized that it was clearly identified in merged PR that this is already implemented for both types of targets. We are just waiting for a similar change in the 'source' field now...

4szt4l commented 1 year ago

This should be added to targets as well, if possible. E.g. replace some values in deployments having a specific annotation or label.

morix1500 commented 1 year ago

/assign