Add Cloud Foundry routes as a source

This commit is contained in:
Dave Grizzanti 2019-03-31 15:50:44 -04:00
parent 3b44e39262
commit b529a92d5b
4 changed files with 107 additions and 1 deletions

View File

@ -82,6 +82,9 @@ func main() {
KubeMaster: cfg.Master, KubeMaster: cfg.Master,
ServiceTypeFilter: cfg.ServiceTypeFilter, ServiceTypeFilter: cfg.ServiceTypeFilter,
IstioIngressGatewayServices: cfg.IstioIngressGatewayServices, IstioIngressGatewayServices: cfg.IstioIngressGatewayServices,
CFAPIEndpoint: cfg.CFAPIEndpoint,
CFUsername: cfg.CFUsername,
CFPassword: cfg.CFPassword,
} }
// Lookup all the selected sources by names and pass them the desired configuration. // Lookup all the selected sources by names and pass them the desired configuration.

View File

@ -105,6 +105,9 @@ type Config struct {
CRDSourceAPIVersion string CRDSourceAPIVersion string
CRDSourceKind string CRDSourceKind string
ServiceTypeFilter []string ServiceTypeFilter []string
CFAPIEndpoint string
CFUsername string
CFPassword string
RFC2136Host string RFC2136Host string
RFC2136Port int RFC2136Port int
RFC2136Zone string RFC2136Zone string
@ -182,6 +185,9 @@ var defaultConfig = &Config{
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
CRDSourceKind: "DNSEndpoint", CRDSourceKind: "DNSEndpoint",
ServiceTypeFilter: []string{}, ServiceTypeFilter: []string{},
CFAPIEndpoint: "",
CFUsername: "",
CFPassword: ""
RFC2136Host: "", RFC2136Host: "",
RFC2136Port: 0, RFC2136Port: 0,
RFC2136Zone: "", RFC2136Zone: "",
@ -245,8 +251,13 @@ func (cfg *Config) ParseFlags(args []string) error {
// Flags related to Istio // Flags related to Istio
app.Flag("istio-ingress-gateway", "The fully-qualified name of the Istio ingress gateway service. Flag can be specified multiple times (default: istio-system/istio-ingressgateway)").Default("istio-system/istio-ingressgateway").StringsVar(&cfg.IstioIngressGatewayServices) app.Flag("istio-ingress-gateway", "The fully-qualified name of the Istio ingress gateway service. Flag can be specified multiple times (default: istio-system/istio-ingressgateway)").Default("istio-system/istio-ingressgateway").StringsVar(&cfg.IstioIngressGatewayServices)
// Flags related to cloud foundry
app.Flag("cf-api-endpoint", "The fully-qualified domain name of the cloud foundry instance you are targeting").Default(defaultConfig.CFAPIEndpoint).StringVar(&cfg.CFAPIEndpoint)
app.Flag("cf-username", "The username to log into the cloud foundry API").Default(defaultConfig.CFUsername).StringVar(&cfg.CFUsername)
app.Flag("cf-password", "The password to log into the cloud foundry API").Default(defaultConfig.CFPassword).StringVar(&cfg.CFPassword)
// Flags related to processing sources // Flags related to processing sources
app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, fake, connector, istio-gateway, crd").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "istio-gateway", "fake", "connector", "crd") app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, fake, connector, istio-gateway, crd").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "istio-gateway", "route", "fake", "connector", "crd")
app.Flag("namespace", "Limit sources of endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace) 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("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("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("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)

58
source/route.go Normal file
View File

@ -0,0 +1,58 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package source
import (
"net/url"
cfclient "github.com/cloudfoundry-community/go-cfclient"
"github.com/kubernetes-incubator/external-dns/endpoint"
)
type routeSource struct {
client *cfclient.Client
}
// NewRouteSource creates a new routeSource with the given config
func NewRouteSource(cfClient *cfclient.Client) (Source, error) {
return &routeSource{
client: cfClient,
}, nil
}
// Endpoints returns endpoint objects
func (rs *routeSource) Endpoints() ([]*endpoint.Endpoint, error) {
endpoints := []*endpoint.Endpoint{}
u, err := url.Parse(rs.client.Config.ApiAddress)
if err != nil {
panic(err)
}
domains, _ := rs.client.ListDomains()
for _, domain := range domains {
q := url.Values{}
q.Set("q", "domain_guid:"+domain.Guid)
routes, _ := rs.client.ListRoutesByQuery(q)
for _, element := range routes {
endpoints = append(endpoints,
endpoint.NewEndpointWithTTL(element.Host+"."+domain.Name, endpoint.RecordTypeCNAME, 300, u.Host))
}
}
return endpoints, nil
}

View File

@ -25,6 +25,7 @@ import (
"sync" "sync"
cfclient "github.com/cloudfoundry-community/go-cfclient"
"github.com/linki/instrumented_http" "github.com/linki/instrumented_http"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
istiocrd "istio.io/istio/pilot/pkg/config/kube/crd" istiocrd "istio.io/istio/pilot/pkg/config/kube/crd"
@ -53,12 +54,16 @@ type Config struct {
KubeMaster string KubeMaster string
ServiceTypeFilter []string ServiceTypeFilter []string
IstioIngressGatewayServices []string IstioIngressGatewayServices []string
CFAPIEndpoint string
CFUsername string
CFPassword string
} }
// ClientGenerator provides clients // ClientGenerator provides clients
type ClientGenerator interface { type ClientGenerator interface {
KubeClient() (kubernetes.Interface, error) KubeClient() (kubernetes.Interface, error)
IstioClient() (istiomodel.ConfigStore, error) IstioClient() (istiomodel.ConfigStore, error)
CloudFoundryClient(cfAPPEndpoint string, cfUsername string, cfPassword string) (*cfclient.Client, error)
} }
// SingletonClientGenerator stores provider clients and guarantees that only one instance of client // SingletonClientGenerator stores provider clients and guarantees that only one instance of client
@ -69,8 +74,10 @@ type SingletonClientGenerator struct {
RequestTimeout time.Duration RequestTimeout time.Duration
kubeClient kubernetes.Interface kubeClient kubernetes.Interface
istioClient istiomodel.ConfigStore istioClient istiomodel.ConfigStore
cfClient *cfclient.Client
kubeOnce sync.Once kubeOnce sync.Once
istioOnce sync.Once istioOnce sync.Once
cfOnce sync.Once
} }
// KubeClient generates a kube client if it was not created before // KubeClient generates a kube client if it was not created before
@ -91,6 +98,27 @@ func (p *SingletonClientGenerator) IstioClient() (istiomodel.ConfigStore, error)
return p.istioClient, err return p.istioClient, err
} }
// CloudFoundryClient generates a cf client if it was not created before
func (p *SingletonClientGenerator) CloudFoundryClient(cfAPIEndpoint string, cfUsername string, cfPassword string) (*cfclient.Client, error) {
var err error
p.cfOnce.Do(func() {
p.cfClient, err = NewCFClient(cfAPIEndpoint, cfUsername, cfPassword)
})
return p.cfClient, err
}
// NewCFClient return a new CF client object.
func NewCFClient(cfAPIEndpoint string, cfUsername string, cfPassword string) (*cfclient.Client, error) {
c := &cfclient.Config{
ApiAddress: "https://" + cfAPIEndpoint,
Username: cfUsername,
Password: cfPassword,
}
client, _ := cfclient.NewClient(c)
return client, nil
}
// ByNames returns multiple Sources given multiple names. // ByNames returns multiple Sources given multiple names.
func ByNames(p ClientGenerator, names []string, cfg *Config) ([]Source, error) { func ByNames(p ClientGenerator, names []string, cfg *Config) ([]Source, error) {
sources := []Source{} sources := []Source{}
@ -130,6 +158,12 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err
return nil, err return nil, err
} }
return NewIstioGatewaySource(kubernetesClient, istioClient, cfg.IstioIngressGatewayServices, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation) return NewIstioGatewaySource(kubernetesClient, istioClient, cfg.IstioIngressGatewayServices, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation)
case "route":
cfClient, err := p.CloudFoundryClient(cfg.CFAPIEndpoint, cfg.CFUsername, cfg.CFPassword)
if err != nil {
return nil, err
}
return NewRouteSource(cfClient)
case "fake": case "fake":
return NewFakeSource(cfg.FQDNTemplate) return NewFakeSource(cfg.FQDNTemplate)
case "connector": case "connector":