I'm upgrading from the operator SDK 0.10.0 to 0.11.0 and I'm having some trouble in migrating a specific code.
According to the changelog, I have to move from &client.ListOptions{} to []client.ListOption{}. We have a code that was using SetLabelSelector to set an option to retrieve all objects of a certain type containing a label key, independent of the value. What's the current way to accomplish that, given that SetLabelSelector doesn't seem to exist anymore?
func (b *Background) cleanDeployments() {
...
deployOpts := &client.ListOptions{}
// Only select fields that have the label 'sidecar.jaegertracing.io/injected'
if err := deployOpts.SetLabelSelector(inject.Label); err != nil {
log.WithError(err).Error("error cleaning orphaned deployment")
}
...
if err := b.cl.List(context.Background(), deployOpts, deployments); err != nil {
log.WithError(err).Error("error cleaning orphaned deployment")
}
}
Workaround:
func (b *Background) cleanDeployments() {
...
deployOpts := []client.ListOption{
matchingLabelKeys(map[string]string{inject.Label: ""}),
}
...
if err := b.cl.List(context.Background(), deployments, deployOpts...); err != nil {
log.WithError(err).Error("error cleaning orphaned deployment")
}
}
type matchingLabelKeys map[string]string
func (m matchingLabelKeys) ApplyToList(opts *client.ListOptions) {
sel := labels.NewSelector()
for k := range map[string]string(m) {
req, err := labels.NewRequirement(k, selection.Exists, []string{})
if err != nil {
log.Warnf("failed to build label selector: %v", err)
return
}
sel.Add(*req)
}
opts.LabelSelector = sel
}
@jpkrohling You should be able to use the client.MatchingLabels() option to set the LabelSelector for your ListOption.
deployOpts := []client.ListOption{
client.MatchingLabels{inject.Label: ""},
client.InNamespace("foo"),
...
}
b.cl.List(context.Background(), deployments, deployOpts...)
It's pretty much the same thing as your workaround.
That's my source of inspiration. The problem with that is that it calls labels.SelectorFromSet(), which later calls labels.NewRequirement(k, selection.Equal, []string{}), so that both the key and the value has to match. Note how I use selection.Exists in my snippet, so that I only check for the key's existence.
Hi @jpkrohling,
Following a suggestion. The following code will List all Deployments in the namespace = foo and wth the label app=example-label.
labelSelector := labels.SelectorFromSet(map[string]string{"app": "example-label"})
listOps := &client.ListOptions{Namespace: "foo", LabelSelector: labelSelector}
deploymentList := &v1.DeploymentList{}
err := client.List(context.TODO(), deploymentList, listOps)
if err != nil {
return nil, err
}
Also, you can check a similar code impl working well here
Please, let us know if it is what you are looking for and if we can close this one.
@camilamacedo86, my use case is somewhat different: I want all deployments with a label key app, not caring about the label's value.
When using SelectorFromSet, it uses the operator selection.Equals, which will use the value for comparison as well. I need a SelectorFromSet that uses selection.Exists instead.
@hasbro17, I just tried your example, and it attempts to also match a value (empty). In case you want to try it out on a concrete case, this is the relevant code and this here is the test that asserts the right behavior.
@jpkrohling Ah, you're right I misread what you were trying to do initially.
I need to test this out but can you try setting the MatchingLabelsSelector option in that case?
Still a bit wonky setting up the selector but that's something that we might need to make easier upstream.
sel := labels.NewSelector()
req, err := labels.NewRequirement("mykey", selection.Exists, []string{})
if err != nil {
....
}
sel.Add(*req)
deployOpts := []client.ListOption{
client.MatchingLabelsSelector{Selector: sel},
...
}
b.cl.List(context.Background(), deployments, deployOpts...)
HI @jpkrohling,
I am closing this one since shows that the above comment answered your question. Also, note that it is more related to k8s projects instead of SDK since it came from https://github.com/kubernetes-sigs/controller-runtime.
However, please feel free to re-open it if you see that is required.
+1, the code from @hasbro17 is similar to what I have in the first comment and what I ended up using. I still think there could be a shortcut, but I can live without it.
Most helpful comment
@jpkrohling Ah, you're right I misread what you were trying to do initially.
I need to test this out but can you try setting the MatchingLabelsSelector option in that case?
Still a bit wonky setting up the selector but that's something that we might need to make easier upstream.