Commit b529a92d authored by Dave Grizzanti's avatar Dave Grizzanti
Browse files

Add Cloud Foundry routes as a source

parent 3b44e392
......@@ -82,6 +82,9 @@ func main() {
KubeMaster: cfg.Master,
ServiceTypeFilter: cfg.ServiceTypeFilter,
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.
......
......@@ -105,6 +105,9 @@ type Config struct {
CRDSourceAPIVersion string
CRDSourceKind string
ServiceTypeFilter []string
CFAPIEndpoint string
CFUsername string
CFPassword string
RFC2136Host string
RFC2136Port int
RFC2136Zone string
......@@ -182,6 +185,9 @@ var defaultConfig = &Config{
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
CRDSourceKind: "DNSEndpoint",
ServiceTypeFilter: []string{},
CFAPIEndpoint: "",
CFUsername: "",
CFPassword: ""
RFC2136Host: "",
RFC2136Port: 0,
RFC2136Zone: "",
......@@ -245,8 +251,13 @@ func (cfg *Config) ParseFlags(args []string) error {
// 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)
// 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
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("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)
......
/*
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
}
......@@ -25,6 +25,7 @@ import (
"sync"
cfclient "github.com/cloudfoundry-community/go-cfclient"
"github.com/linki/instrumented_http"
log "github.com/sirupsen/logrus"
istiocrd "istio.io/istio/pilot/pkg/config/kube/crd"
......@@ -53,12 +54,16 @@ type Config struct {
KubeMaster string
ServiceTypeFilter []string
IstioIngressGatewayServices []string
CFAPIEndpoint string
CFUsername string
CFPassword string
}
// ClientGenerator provides clients
type ClientGenerator interface {
KubeClient() (kubernetes.Interface, 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
......@@ -69,8 +74,10 @@ type SingletonClientGenerator struct {
RequestTimeout time.Duration
kubeClient kubernetes.Interface
istioClient istiomodel.ConfigStore
cfClient *cfclient.Client
kubeOnce sync.Once
istioOnce sync.Once
cfOnce sync.Once
}
// 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
}
// 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.
func ByNames(p ClientGenerator, names []string, cfg *Config) ([]Source, error) {
sources := []Source{}
......@@ -130,6 +158,12 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err
return nil, err
}
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":
return NewFakeSource(cfg.FQDNTemplate)
case "connector":
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment