Repository: google/kf
Pull request #534 (2019-08-16 19:38:52)

do not base64 decode vcap services
<!-- Include the issue number below -->

## Proposed Changes

*
*
*

## Release Notes

<!-- kf follows the Keep A Changelog standard for release notes.

https://keepachangelog.com/en/1.0.0/

Changelog entries should be one per line and start with one of the following
words:

`Added` for new features.
`Changed` for changes in existing functionality.
`Deprecated` for soon-to-be removed features.
`Removed` for now removed features.
`Fixed` for any bug fixes.
`Security` in case of vulnerabilities.

If one of the changes is breaking include that as a second word e.g.

  Removed BREAKING support for manifests v1
-->

```release-note
Fixed vcap-service double decoding secrets
```


mattysweeps: > Is the value already decoded, or are we now returning the encoded value?

It is already decoded

Patch:
diff --git a/docs/kf.dev/content/en/docs/developers/env/_index.md b/docs/kf.dev/content/en/docs/developers/env/_index.md
new file mode 100644
index 0000000..6074438
--- /dev/null
+++ b/docs/kf.dev/content/en/docs/developers/env/_index.md
@@ -0,0 +1,7 @@
+---
+title: "Environment"
+linkTitle: "Environment"
+weight: 40
+description: >
+  Learn how to use environment variables in applications deployed with Kf.
+---
diff --git a/docs/kf.dev/content/en/docs/developers/env/defaults/_index.md b/docs/kf.dev/content/en/docs/developers/env/defaults/_index.md
new file mode 100644
index 0000000..a130fcd
--- /dev/null
+++ b/docs/kf.dev/content/en/docs/developers/env/defaults/_index.md
@@ -0,0 +1,31 @@
+---
+title: "Default Environment Variables"
+linkTitle: "Default Environment Variables"
+weight: 30
+description: >
+  Learn about the default environment variables available to an application in
+  Kf and how they compare to CF.
+---
+
+## Compared to CF
+
+The following table lists default environment variables available to an
+application deployed to Cloud Foundry and includes a column indicating if that
+variable is available by default in Kf.
+
+| Name                    | Available in Kf? |
+| ---                     | ---              |
+| VCAP_SERVICES           | ✔️                |
+| VCAP_APPLICATION        | ✔️                |
+| VCAP_APP_HOST           | 🚫               |
+| VCAP_APP_PORT           | 🚫               |
+| CF_INSTANCE_ADDR        | 🚫               |
+| CF_INSTANCE_CERT        | 🚫               |
+| CF_INSTANCE_GUID        | 🚫               |
+| CF_INSTANCE_INDEX       | 🚫               |
+| CF_INSTANCE_INTERNAL_IP | 🚫               |
+| CF_INSTANCE_IP          | 🚫               |
+| CF_INSTANCE_KEY         | 🚫               |
+| CF_INSTANCE_PORT        | 🚫               |
+| CF_INSTANCE_PORTS       | 🚫               |
+| CF_SYSTEM_CERT_PATH     | 🚫               |
diff --git a/pkg/kf/apps/zz_generated.client.go b/pkg/kf/apps/zz_generated.client.go
index 1bc06ee..b83f28c 100644
--- a/pkg/kf/apps/zz_generated.client.go
+++ b/pkg/kf/apps/zz_generated.client.go
@@ -314,7 +314,7 @@ type Merger func(newObj, oldObj *v1alpha1.App) *v1alpha1.App
 func (core *coreClient) Upsert(namespace string, newObj *v1alpha1.App, merge Merger) (*v1alpha1.App, error) {
 	// NOTE: the field selector may be ignored by some Kubernetes resources
 	// so we double check down below.
-	existing, err := core.List(namespace, WithListfieldSelector(map[string]string{"metadata.name": newObj.Name}))
+	existing, err := core.List(namespace, WithListFieldSelector(map[string]string{"metadata.name": newObj.Name}))
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/kf/apps/zz_generated.clientoptions.go b/pkg/kf/apps/zz_generated.clientoptions.go
index 84bebf5..85f8255 100644
--- a/pkg/kf/apps/zz_generated.clientoptions.go
+++ b/pkg/kf/apps/zz_generated.clientoptions.go
@@ -235,22 +235,22 @@ func (opts ListOptions) labelSelector() map[string]string {
 	return opts.toConfig().labelSelector
 }
 
-// WithListfieldSelector creates an Option that sets A selector on the resource's fields.
-func WithListfieldSelector(val map[string]string) ListOption {
+// WithListFieldSelector creates an Option that sets A selector on the resource's fields.
+func WithListFieldSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.fieldSelector = val
 	}
 }
 
-// WithListfilters creates an Option that sets Additional filters to apply.
-func WithListfilters(val []Predicate) ListOption {
+// WithListFilters creates an Option that sets Additional filters to apply.
+func WithListFilters(val []Predicate) ListOption {
 	return func(cfg *listConfig) {
 		cfg.filters = val
 	}
 }
 
-// WithListlabelSelector creates an Option that sets A label selector.
-func WithListlabelSelector(val map[string]string) ListOption {
+// WithListLabelSelector creates an Option that sets A label selector.
+func WithListLabelSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.labelSelector = val
 	}
diff --git a/pkg/kf/commands/routes/delete_route.go b/pkg/kf/commands/routes/delete_route.go
index c7c9114..8b918fd 100644
--- a/pkg/kf/commands/routes/delete_route.go
+++ b/pkg/kf/commands/routes/delete_route.go
@@ -63,7 +63,7 @@ func NewDeleteRouteCommand(
 			// routes with the proper labels first, then use their apps.
 			apps, err := a.List(
 				p.Namespace,
-				apps.WithListfilters([]apps.Predicate{
+				apps.WithListFilters([]apps.Predicate{
 					func(app *v1alpha1.App) bool {
 						return algorithms.Search(
 							0,
diff --git a/pkg/kf/commands/service-bindings/vcap_services.go b/pkg/kf/commands/service-bindings/vcap_services.go
index 8d03623..05def9a 100644
--- a/pkg/kf/commands/service-bindings/vcap_services.go
+++ b/pkg/kf/commands/service-bindings/vcap_services.go
@@ -15,7 +15,6 @@
 package servicebindings
 
 import (
-	"encoding/base64"
 	"errors"
 	"fmt"
 
@@ -58,12 +57,7 @@ func NewVcapServicesCommand(
 				return errors.New("VCAP_SERVICES does not exist")
 			}
 
-			decoded, err := base64.StdEncoding.DecodeString(string(vcapServices))
-			if err != nil {
-				return err
-			}
-
-			fmt.Fprintln(cmd.OutOrStdout(), string(decoded))
+			fmt.Fprintln(cmd.OutOrStdout(), string(vcapServices))
 			return nil
 		},
 	}
diff --git a/pkg/kf/internal/tools/clientgen/tmplclient.go b/pkg/kf/internal/tools/clientgen/tmplclient.go
index e26091f..5e38052 100644
--- a/pkg/kf/internal/tools/clientgen/tmplclient.go
+++ b/pkg/kf/internal/tools/clientgen/tmplclient.go
@@ -184,7 +184,7 @@ type Merger func(newObj, oldObj *{{.Type}}) *{{.Type}}
 func (core *coreClient) Upsert({{ $nssig }} newObj *{{.Type}}, merge Merger) (*{{.Type}}, error) {
 	// NOTE: the field selector may be ignored by some Kubernetes resources
 	// so we double check down below.
-	existing, err := core.List({{ $nsparam }} WithListfieldSelector(map[string]string{"metadata.name": newObj.Name}))
+	existing, err := core.List({{ $nsparam }} WithListFieldSelector(map[string]string{"metadata.name": newObj.Name}))
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/kf/internal/tools/generator/gen.go b/pkg/kf/internal/tools/generator/gen.go
index fbedc9d..91ca0e0 100644
--- a/pkg/kf/internal/tools/generator/gen.go
+++ b/pkg/kf/internal/tools/generator/gen.go
@@ -18,6 +18,7 @@ import (
 	"bytes"
 	"fmt"
 	"sort"
+	"strings"
 	"text/template"
 	"time"
 )
@@ -85,5 +86,6 @@ func TemplateFuncs() template.FuncMap {
 		"genlicense": GenLicense,
 		"genimports": GenImports,
 		"gennotice":  GenNotice,
+		"title":      strings.Title,
 	}
 }
diff --git a/pkg/kf/internal/tools/option-builder/option-builder.go b/pkg/kf/internal/tools/option-builder/option-builder.go
index 99c2232..b77ace3 100755
--- a/pkg/kf/internal/tools/option-builder/option-builder.go
+++ b/pkg/kf/internal/tools/option-builder/option-builder.go
@@ -164,8 +164,8 @@ func (opts {{ $typeoptarr }}) {{$opt.Name}}() {{ $opt.Type }} {
 {{ end }}
 {{ range $i, $opt := .Options}}
 
-// With{{$globalName}}{{$opt.Name}} creates an Option that sets {{$opt.Description}}
-func With{{$globalName}}{{$opt.Name}}(val {{ $opt.Type }}) {{ $typeopt }} {
+// With{{title $globalName}}{{title $opt.Name}} creates an Option that sets {{$opt.Description}}
+func With{{title $globalName}}{{title $opt.Name}}(val {{ $opt.Type }}) {{ $typeopt }} {
   return func(cfg *{{ $typecfg }}) {
     cfg.{{$opt.Name}} = val
   }
@@ -176,7 +176,7 @@ func With{{$globalName}}{{$opt.Name}}(val {{ $opt.Type }}) {{ $typeopt }} {
 // {{$globalName}}OptionDefaults gets the default values for {{$globalName}}.
 func {{$globalName}}OptionDefaults() {{ $typeoptarr }} {
 	return {{ $typeoptarr }}{
-		{{ range $i, $opt := .Options}}{{ if $opt.Default }}With{{$globalName}}{{$opt.Name}}({{ $opt.Default }}),
+		{{ range $i, $opt := .Options}}{{ if $opt.Default }}With{{title $globalName}}{{title $opt.Name}}({{ $opt.Default }}),
 		{{ end }}{{ end }}
 	}
 }
diff --git a/pkg/kf/routeclaims/zz_generated.client.go b/pkg/kf/routeclaims/zz_generated.client.go
index 6b17076..38e134d 100644
--- a/pkg/kf/routeclaims/zz_generated.client.go
+++ b/pkg/kf/routeclaims/zz_generated.client.go
@@ -314,7 +314,7 @@ type Merger func(newObj, oldObj *v1alpha1.RouteClaim) *v1alpha1.RouteClaim
 func (core *coreClient) Upsert(namespace string, newObj *v1alpha1.RouteClaim, merge Merger) (*v1alpha1.RouteClaim, error) {
 	// NOTE: the field selector may be ignored by some Kubernetes resources
 	// so we double check down below.
-	existing, err := core.List(namespace, WithListfieldSelector(map[string]string{"metadata.name": newObj.Name}))
+	existing, err := core.List(namespace, WithListFieldSelector(map[string]string{"metadata.name": newObj.Name}))
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/kf/routeclaims/zz_generated.clientoptions.go b/pkg/kf/routeclaims/zz_generated.clientoptions.go
index 9ceadb1..6c401bc 100644
--- a/pkg/kf/routeclaims/zz_generated.clientoptions.go
+++ b/pkg/kf/routeclaims/zz_generated.clientoptions.go
@@ -235,22 +235,22 @@ func (opts ListOptions) labelSelector() map[string]string {
 	return opts.toConfig().labelSelector
 }
 
-// WithListfieldSelector creates an Option that sets A selector on the resource's fields.
-func WithListfieldSelector(val map[string]string) ListOption {
+// WithListFieldSelector creates an Option that sets A selector on the resource's fields.
+func WithListFieldSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.fieldSelector = val
 	}
 }
 
-// WithListfilters creates an Option that sets Additional filters to apply.
-func WithListfilters(val []Predicate) ListOption {
+// WithListFilters creates an Option that sets Additional filters to apply.
+func WithListFilters(val []Predicate) ListOption {
 	return func(cfg *listConfig) {
 		cfg.filters = val
 	}
 }
 
-// WithListlabelSelector creates an Option that sets A label selector.
-func WithListlabelSelector(val map[string]string) ListOption {
+// WithListLabelSelector creates an Option that sets A label selector.
+func WithListLabelSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.labelSelector = val
 	}
diff --git a/pkg/kf/routes/zz_generated.client.go b/pkg/kf/routes/zz_generated.client.go
index d3e78ed..6aa8d2f 100644
--- a/pkg/kf/routes/zz_generated.client.go
+++ b/pkg/kf/routes/zz_generated.client.go
@@ -314,7 +314,7 @@ type Merger func(newObj, oldObj *v1alpha1.Route) *v1alpha1.Route
 func (core *coreClient) Upsert(namespace string, newObj *v1alpha1.Route, merge Merger) (*v1alpha1.Route, error) {
 	// NOTE: the field selector may be ignored by some Kubernetes resources
 	// so we double check down below.
-	existing, err := core.List(namespace, WithListfieldSelector(map[string]string{"metadata.name": newObj.Name}))
+	existing, err := core.List(namespace, WithListFieldSelector(map[string]string{"metadata.name": newObj.Name}))
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/kf/routes/zz_generated.clientoptions.go b/pkg/kf/routes/zz_generated.clientoptions.go
index 73bd41d..fca2bf8 100644
--- a/pkg/kf/routes/zz_generated.clientoptions.go
+++ b/pkg/kf/routes/zz_generated.clientoptions.go
@@ -235,22 +235,22 @@ func (opts ListOptions) labelSelector() map[string]string {
 	return opts.toConfig().labelSelector
 }
 
-// WithListfieldSelector creates an Option that sets A selector on the resource's fields.
-func WithListfieldSelector(val map[string]string) ListOption {
+// WithListFieldSelector creates an Option that sets A selector on the resource's fields.
+func WithListFieldSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.fieldSelector = val
 	}
 }
 
-// WithListfilters creates an Option that sets Additional filters to apply.
-func WithListfilters(val []Predicate) ListOption {
+// WithListFilters creates an Option that sets Additional filters to apply.
+func WithListFilters(val []Predicate) ListOption {
 	return func(cfg *listConfig) {
 		cfg.filters = val
 	}
 }
 
-// WithListlabelSelector creates an Option that sets A label selector.
-func WithListlabelSelector(val map[string]string) ListOption {
+// WithListLabelSelector creates an Option that sets A label selector.
+func WithListLabelSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.labelSelector = val
 	}
diff --git a/pkg/kf/sources/zz_generated.client.go b/pkg/kf/sources/zz_generated.client.go
index 100851e..db99143 100644
--- a/pkg/kf/sources/zz_generated.client.go
+++ b/pkg/kf/sources/zz_generated.client.go
@@ -314,7 +314,7 @@ type Merger func(newObj, oldObj *v1alpha1.Source) *v1alpha1.Source
 func (core *coreClient) Upsert(namespace string, newObj *v1alpha1.Source, merge Merger) (*v1alpha1.Source, error) {
 	// NOTE: the field selector may be ignored by some Kubernetes resources
 	// so we double check down below.
-	existing, err := core.List(namespace, WithListfieldSelector(map[string]string{"metadata.name": newObj.Name}))
+	existing, err := core.List(namespace, WithListFieldSelector(map[string]string{"metadata.name": newObj.Name}))
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/kf/sources/zz_generated.clientoptions.go b/pkg/kf/sources/zz_generated.clientoptions.go
index bd7347c..bfac3f7 100644
--- a/pkg/kf/sources/zz_generated.clientoptions.go
+++ b/pkg/kf/sources/zz_generated.clientoptions.go
@@ -235,22 +235,22 @@ func (opts ListOptions) labelSelector() map[string]string {
 	return opts.toConfig().labelSelector
 }
 
-// WithListfieldSelector creates an Option that sets A selector on the resource's fields.
-func WithListfieldSelector(val map[string]string) ListOption {
+// WithListFieldSelector creates an Option that sets A selector on the resource's fields.
+func WithListFieldSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.fieldSelector = val
 	}
 }
 
-// WithListfilters creates an Option that sets Additional filters to apply.
-func WithListfilters(val []Predicate) ListOption {
+// WithListFilters creates an Option that sets Additional filters to apply.
+func WithListFilters(val []Predicate) ListOption {
 	return func(cfg *listConfig) {
 		cfg.filters = val
 	}
 }
 
-// WithListlabelSelector creates an Option that sets A label selector.
-func WithListlabelSelector(val map[string]string) ListOption {
+// WithListLabelSelector creates an Option that sets A label selector.
+func WithListLabelSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.labelSelector = val
 	}
diff --git a/pkg/kf/spaces/zz_generated.client.go b/pkg/kf/spaces/zz_generated.client.go
index 4f67f02..4173d9b 100644
--- a/pkg/kf/spaces/zz_generated.client.go
+++ b/pkg/kf/spaces/zz_generated.client.go
@@ -314,7 +314,7 @@ type Merger func(newObj, oldObj *v1alpha1.Space) *v1alpha1.Space
 func (core *coreClient) Upsert(newObj *v1alpha1.Space, merge Merger) (*v1alpha1.Space, error) {
 	// NOTE: the field selector may be ignored by some Kubernetes resources
 	// so we double check down below.
-	existing, err := core.List(WithListfieldSelector(map[string]string{"metadata.name": newObj.Name}))
+	existing, err := core.List(WithListFieldSelector(map[string]string{"metadata.name": newObj.Name}))
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/kf/spaces/zz_generated.clientoptions.go b/pkg/kf/spaces/zz_generated.clientoptions.go
index 1d1ad8f..6a30ce9 100644
--- a/pkg/kf/spaces/zz_generated.clientoptions.go
+++ b/pkg/kf/spaces/zz_generated.clientoptions.go
@@ -235,22 +235,22 @@ func (opts ListOptions) labelSelector() map[string]string {
 	return opts.toConfig().labelSelector
 }
 
-// WithListfieldSelector creates an Option that sets A selector on the resource's fields.
-func WithListfieldSelector(val map[string]string) ListOption {
+// WithListFieldSelector creates an Option that sets A selector on the resource's fields.
+func WithListFieldSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.fieldSelector = val
 	}
 }
 
-// WithListfilters creates an Option that sets Additional filters to apply.
-func WithListfilters(val []Predicate) ListOption {
+// WithListFilters creates an Option that sets Additional filters to apply.
+func WithListFilters(val []Predicate) ListOption {
 	return func(cfg *listConfig) {
 		cfg.filters = val
 	}
 }
 
-// WithListlabelSelector creates an Option that sets A label selector.
-func WithListlabelSelector(val map[string]string) ListOption {
+// WithListLabelSelector creates an Option that sets A label selector.
+func WithListLabelSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.labelSelector = val
 	}


Test patch:
diff --git a/pkg/kf/commands/service-bindings/vcap_services_test.go b/pkg/kf/commands/service-bindings/vcap_services_test.go
index 56b66de..fc95d9e 100644
--- a/pkg/kf/commands/service-bindings/vcap_services_test.go
+++ b/pkg/kf/commands/service-bindings/vcap_services_test.go
@@ -16,8 +16,9 @@ package servicebindings_test
 
 import (
 	"bytes"
-	"encoding/base64"
+	"encoding/json"
 	"errors"
+	"fmt"
 	"testing"
 
 	"github.com/google/kf/pkg/kf/commands/config"
@@ -25,7 +26,6 @@ import (
 	"github.com/google/kf/pkg/kf/commands/utils"
 	"github.com/google/kf/pkg/kf/testutil"
 	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	k8sfake "k8s.io/client-go/kubernetes/fake"
 )
 
@@ -38,18 +38,29 @@ func TestNewVcapServicesCommand(t *testing.T) {
 		ExpectedStrings []string
 	}
 
-	data := []byte(`{"some":"services"}`)
-	encodedData := base64.StdEncoding.EncodeToString(data)
+	secretSerialized := `{
+    "apiVersion": "v1",
+    "data": {
+        "VCAP_SERVICES": "eyJzb21lIjoic2VydmljZXMifQ=="
+    },
+    "kind": "Secret",
+    "metadata": {
+        "labels": {
+            "app.kubernetes.io/component": "secret",
+            "app.kubernetes.io/managed-by": "kf",
+            "app.kubernetes.io/name": "APP_NAME"
+        },
+        "name": "kf-injected-envs-APP_NAME",
+        "namespace": "custom-ns"
+    },
+    "type": "Opaque"
+}
+	`
 
-	secret := &corev1.Secret{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      "kf-injected-envs-APP_NAME",
-			Namespace: "custom-ns",
-		},
-		Data: map[string][]byte{
-			"VCAP_SERVICES": []byte(encodedData),
-		},
-	}
+	var secret *corev1.Secret
+	err := json.Unmarshal([]byte(secretSerialized), &secret)
+	fmt.Println(secret.Name)
+	testutil.AssertNil(t, "err", err)
 	k8sclient := k8sfake.NewSimpleClientset(secret)
 
 	cases := map[string]serviceTest{
diff --git a/pkg/kf/internal/tools/clientgen/gentest/zz_generated.client.go b/pkg/kf/internal/tools/clientgen/gentest/zz_generated.client.go
index acd316b..eed9980 100644
--- a/pkg/kf/internal/tools/clientgen/gentest/zz_generated.client.go
+++ b/pkg/kf/internal/tools/clientgen/gentest/zz_generated.client.go
@@ -314,7 +314,7 @@ type Merger func(newObj, oldObj *v1.Secret) *v1.Secret
 func (core *coreClient) Upsert(namespace string, newObj *v1.Secret, merge Merger) (*v1.Secret, error) {
 	// NOTE: the field selector may be ignored by some Kubernetes resources
 	// so we double check down below.
-	existing, err := core.List(namespace, WithListfieldSelector(map[string]string{"metadata.name": newObj.Name}))
+	existing, err := core.List(namespace, WithListFieldSelector(map[string]string{"metadata.name": newObj.Name}))
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/kf/internal/tools/clientgen/gentest/zz_generated.clientoptions.go b/pkg/kf/internal/tools/clientgen/gentest/zz_generated.clientoptions.go
index b7458ad..9bf2e54 100644
--- a/pkg/kf/internal/tools/clientgen/gentest/zz_generated.clientoptions.go
+++ b/pkg/kf/internal/tools/clientgen/gentest/zz_generated.clientoptions.go
@@ -235,22 +235,22 @@ func (opts ListOptions) labelSelector() map[string]string {
 	return opts.toConfig().labelSelector
 }
 
-// WithListfieldSelector creates an Option that sets A selector on the resource's fields.
-func WithListfieldSelector(val map[string]string) ListOption {
+// WithListFieldSelector creates an Option that sets A selector on the resource's fields.
+func WithListFieldSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.fieldSelector = val
 	}
 }
 
-// WithListfilters creates an Option that sets Additional filters to apply.
-func WithListfilters(val []Predicate) ListOption {
+// WithListFilters creates an Option that sets Additional filters to apply.
+func WithListFilters(val []Predicate) ListOption {
 	return func(cfg *listConfig) {
 		cfg.filters = val
 	}
 }
 
-// WithListlabelSelector creates an Option that sets A label selector.
-func WithListlabelSelector(val map[string]string) ListOption {
+// WithListLabelSelector creates an Option that sets A label selector.
+func WithListLabelSelector(val map[string]string) ListOption {
 	return func(cfg *listConfig) {
 		cfg.labelSelector = val
 	}