Added labelFilter for source CRD (#1461)

* Added label filter for source CRD

* Fixed bug with labels and added tests for source CRD

* Fixed formating

* Update source/crd_test.go

Co-authored-by: Vinny Sabatini <vincent.sabatini@gmail.com>

Co-authored-by: Vinny Sabatini <vincent.sabatini@gmail.com>
This commit is contained in:
João Marçal 2020-09-24 10:28:05 +02:00 committed by GitHub
parent 32fedeaf07
commit 79ea64884b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 6 deletions

View File

@ -100,6 +100,7 @@ func main() {
sourceCfg := &source.Config{
Namespace: cfg.Namespace,
AnnotationFilter: cfg.AnnotationFilter,
LabelFilter: cfg.LabelFilter,
FQDNTemplate: cfg.FQDNTemplate,
CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation,
IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation,

View File

@ -47,6 +47,7 @@ type Config struct {
Sources []string
Namespace string
AnnotationFilter string
LabelFilter string
FQDNTemplate string
CombineFQDNAndAnnotation bool
IgnoreHostnameAnnotation bool
@ -157,6 +158,7 @@ var defaultConfig = &Config{
Sources: nil,
Namespace: "",
AnnotationFilter: "",
LabelFilter: "",
FQDNTemplate: "",
CombineFQDNAndAnnotation: false,
IgnoreHostnameAnnotation: false,
@ -310,6 +312,7 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("namespace", "Limit sources of endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace)
app.Flag("annotation-filter", "Filter sources managed by external-dns via annotation using label selector semantics (default: all sources)").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter)
app.Flag("label-filter", "Filter sources managed by external-dns via label selector when listing all resources; currently only supported by source CRD").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter)
app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate)
app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation)
app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when using fqdn-template is set (optional, default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation)

View File

@ -43,6 +43,7 @@ type crdSource struct {
crdResource string
codec runtime.ParameterCodec
annotationFilter string
labelFilter string
}
func addKnownTypes(scheme *runtime.Scheme, groupVersion schema.GroupVersion) error {
@ -102,11 +103,12 @@ func NewCRDClientForAPIVersionKind(client kubernetes.Interface, kubeConfig, apiS
}
// NewCRDSource creates a new crdSource with the given config.
func NewCRDSource(crdClient rest.Interface, namespace, kind string, annotationFilter string, scheme *runtime.Scheme) (Source, error) {
func NewCRDSource(crdClient rest.Interface, namespace, kind string, annotationFilter string, labelFilter string, scheme *runtime.Scheme) (Source, error) {
return &crdSource{
crdResource: strings.ToLower(kind) + "s",
namespace: namespace,
annotationFilter: annotationFilter,
labelFilter: labelFilter,
crdClient: crdClient,
codec: runtime.NewParameterCodec(scheme),
}, nil
@ -119,12 +121,22 @@ func (cs *crdSource) AddEventHandler(ctx context.Context, handler func()) {
func (cs *crdSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
endpoints := []*endpoint.Endpoint{}
result, err := cs.List(ctx, &metav1.ListOptions{})
var (
result *endpoint.DNSEndpointList
err error
)
if cs.labelFilter != "" {
result, err = cs.List(ctx, &metav1.ListOptions{LabelSelector: cs.labelFilter})
} else {
result, err = cs.List(ctx, &metav1.ListOptions{})
}
if err != nil {
return nil, err
}
result, err = cs.filterByAnnotations(result)
if err != nil {
return nil, err
}

View File

@ -57,7 +57,7 @@ func objBody(codec runtime.Encoder, obj runtime.Object) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
}
func startCRDServerToServeTargets(endpoints []*endpoint.Endpoint, apiVersion, kind, namespace, name string, annotations map[string]string, t *testing.T) rest.Interface {
func startCRDServerToServeTargets(endpoints []*endpoint.Endpoint, apiVersion, kind, namespace, name string, annotations map[string]string, labels map[string]string, t *testing.T) rest.Interface {
groupVersion, _ := schema.ParseGroupVersion(apiVersion)
scheme := runtime.NewScheme()
addKnownTypes(scheme, groupVersion)
@ -72,6 +72,7 @@ func startCRDServerToServeTargets(endpoints []*endpoint.Endpoint, apiVersion, ki
Name: name,
Namespace: namespace,
Annotations: annotations,
Labels: labels,
Generation: 1,
},
Spec: endpoint.DNSEndpointSpec{
@ -139,7 +140,9 @@ func testCRDSourceEndpoints(t *testing.T) {
expectEndpoints bool
expectError bool
annotationFilter string
labelFilter string
annotations map[string]string
labels map[string]string
}{
{
title: "invalid crd api version",
@ -308,16 +311,56 @@ func testCRDSourceEndpoints(t *testing.T) {
expectEndpoints: true,
expectError: false,
},
{
title: "valid crd gvk with label and non matching label filter",
registeredAPIVersion: "test.k8s.io/v1alpha1",
apiVersion: "test.k8s.io/v1alpha1",
registeredKind: "DNSEndpoint",
kind: "DNSEndpoint",
namespace: "foo",
registeredNamespace: "foo",
labels: map[string]string{"test": "that"},
labelFilter: "test=filter_something_else",
endpoints: []*endpoint.Endpoint{
{DNSName: "abc.example.org",
Targets: endpoint.Targets{"1.2.3.4"},
RecordType: endpoint.RecordTypeA,
RecordTTL: 180,
},
},
expectEndpoints: false,
expectError: false,
},
{
title: "valid crd gvk with label and matching label filter",
registeredAPIVersion: "test.k8s.io/v1alpha1",
apiVersion: "test.k8s.io/v1alpha1",
registeredKind: "DNSEndpoint",
kind: "DNSEndpoint",
namespace: "foo",
registeredNamespace: "foo",
labels: map[string]string{"test": "that"},
labelFilter: "test=that",
endpoints: []*endpoint.Endpoint{
{DNSName: "abc.example.org",
Targets: endpoint.Targets{"1.2.3.4"},
RecordType: endpoint.RecordTypeA,
RecordTTL: 180,
},
},
expectEndpoints: true,
expectError: false,
},
} {
t.Run(ti.title, func(t *testing.T) {
restClient := startCRDServerToServeTargets(ti.endpoints, ti.registeredAPIVersion, ti.registeredKind, ti.registeredNamespace, "test", ti.annotations, t)
restClient := startCRDServerToServeTargets(ti.endpoints, ti.registeredAPIVersion, ti.registeredKind, ti.registeredNamespace, "test", ti.annotations, ti.labels, t)
groupVersion, err := schema.ParseGroupVersion(ti.apiVersion)
require.NoError(t, err)
scheme := runtime.NewScheme()
addKnownTypes(scheme, groupVersion)
cs, _ := NewCRDSource(restClient, ti.namespace, ti.kind, ti.annotationFilter, scheme)
cs, _ := NewCRDSource(restClient, ti.namespace, ti.kind, ti.annotationFilter, ti.labelFilter, scheme)
receivedEndpoints, err := cs.Endpoints(context.Background())
if ti.expectError {

View File

@ -42,6 +42,7 @@ var ErrSourceNotFound = errors.New("source not found")
type Config struct {
Namespace string
AnnotationFilter string
LabelFilter string
FQDNTemplate string
CombineFQDNAndAnnotation bool
IgnoreHostnameAnnotation bool
@ -247,7 +248,7 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err
if err != nil {
return nil, err
}
return NewCRDSource(crdClient, cfg.Namespace, cfg.CRDSourceKind, cfg.AnnotationFilter, scheme)
return NewCRDSource(crdClient, cfg.Namespace, cfg.CRDSourceKind, cfg.AnnotationFilter, cfg.LabelFilter, scheme)
case "skipper-routegroup":
apiServerURL := cfg.APIServerURL
tokenPath := ""