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

feat: add annotation and label filters to Ambassador Host Source #2633

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/sources/sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| Source | Resources | annotation-filter | label-filter |
|---------------------------------|-------------------------------------------------------------------------------|-------------------|--------------|
| ambassador-host | Host.getambassador.io | | |
| ambassador-host | Host.getambassador.io | Yes | Yes |
| connector | | | |
| contour-httpproxy | HttpProxy.projectcontour.io | Yes | |
| cloudfoundry | | | |
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("openshift-router-name", "if source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record.").StringVar(&cfg.OCPRouterName)
app.Flag("namespace", "Limit resources queried for endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace)
app.Flag("annotation-filter", "Filter resources queried for endpoints by annotation, using label selector semantics").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter)
app.Flag("label-filter", "Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, and service").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter)
app.Flag("label-filter", "Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, service and ambassador-host").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter)
app.Flag("ingress-class", "Require an Ingress to have this class name (defaults to any class; specify multiple times to allow more than one class)").StringsVar(&cfg.IngressClassNames)
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)
Expand Down
55 changes: 53 additions & 2 deletions source/ambassador_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ type ambassadorHostSource struct {
dynamicKubeClient dynamic.Interface
kubeClient kubernetes.Interface
namespace string
annotationFilter string
ambassadorHostInformer informers.GenericInformer
unstructuredConverter *unstructuredConverter
labelSelector labels.Selector
}

// NewAmbassadorHostSource creates a new ambassadorHostSource with the given config.
Expand All @@ -67,6 +69,8 @@ func NewAmbassadorHostSource(
dynamicKubeClient dynamic.Interface,
kubeClient kubernetes.Interface,
namespace string,
annotationFilter string,
labelSelector labels.Selector,
) (Source, error) {
var err error

Expand All @@ -85,6 +89,7 @@ func NewAmbassadorHostSource(

informerFactory.Start(ctx.Done())

// wait for the local cache to be populated.
if err := waitForDynamicCacheSync(context.Background(), informerFactory); err != nil {
return nil, err
}
Expand All @@ -98,20 +103,23 @@ func NewAmbassadorHostSource(
dynamicKubeClient: dynamicKubeClient,
kubeClient: kubeClient,
namespace: namespace,
annotationFilter: annotationFilter,
ambassadorHostInformer: ambassadorHostInformer,
unstructuredConverter: uc,
labelSelector: labelSelector,
}, nil
}

// Endpoints returns endpoint objects for each host-target combination that should be processed.
// Retrieves all Hosts in the source's namespace(s).
func (sc *ambassadorHostSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
hosts, err := sc.ambassadorHostInformer.Lister().ByNamespace(sc.namespace).List(labels.Everything())
hosts, err := sc.ambassadorHostInformer.Lister().ByNamespace(sc.namespace).List(sc.labelSelector)
if err != nil {
return nil, err
}

endpoints := []*endpoint.Endpoint{}
// Get a list of Ambassador Host resources
ambassadorHosts := []*ambassador.Host{}
for _, hostObj := range hosts {
unstructuredHost, ok := hostObj.(*unstructured.Unstructured)
if !ok {
Expand All @@ -123,7 +131,18 @@ func (sc *ambassadorHostSource) Endpoints(ctx context.Context) ([]*endpoint.Endp
if err != nil {
return nil, err
}
ambassadorHosts = append(ambassadorHosts, host)
}

// Filter Ambassador Hosts
ambassadorHosts, err = sc.filterByAnnotations(ambassadorHosts)
if err != nil {
return nil, errors.Wrap(err, "failed to filter Ambassador Hosts by annotation")
}

endpoints := []*endpoint.Endpoint{}

for _, host := range ambassadorHosts {
fullname := fmt.Sprintf("%s/%s", host.Namespace, host.Name)

// look for the "exernal-dns.ambassador-service" annotation. If it is not there then just ignore this `Host`
Expand Down Expand Up @@ -272,3 +291,35 @@ func newUnstructuredConverter() (*unstructuredConverter, error) {

return uc, nil
}

// Filter a list of Ambassador Host Resources to only return the ones that
// contain the required External-DNS annotation filter
func (sc *ambassadorHostSource) filterByAnnotations(ambassadorHosts []*ambassador.Host) ([]*ambassador.Host, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having a gazillion of filterByAnnotations([]specificObjects) functions, one could create a generic filterByAnnotations(objects []*meta.ObjectMeta) and use object.GetAnnotations().

Just an observation though. Would be too much for this PR to refactor this.

// External-DNS Annotation Filter
labelSelector, err := metav1.ParseToLabelSelector(sc.annotationFilter)
if err != nil {
return nil, err
}

selector, err := metav1.LabelSelectorAsSelector(labelSelector)
if err != nil {
return nil, err
}

// empty filter returns original list of Ambassador Hosts
if selector.Empty() {
return ambassadorHosts, nil
}

// Return a filtered list of Ambassador Hosts
filteredList := []*ambassador.Host{}
for _, host := range ambassadorHosts {
annotations := labels.Set(host.Annotations)
// include Ambassador Host if its annotations match the annotation filter
if selector.Matches(annotations) {
filteredList = append(filteredList, host)
}
}

return filteredList, nil
}
Loading
Loading