Repository: kubernetes-incubator/external-dns
Pull request #1123 (2019-07-31 11:56:23)

Add FAQ for the new aws-prefer-cname flag
As discussed in https://github.com/kubernetes-incubator/external-dns/pull/1103 this PR adds a FAQ for the new `--aws-prefer-cname` flag.


Patch:
diff --git a/.travis.yml b/.travis.yml
index 28b1a854..5b2f6c83 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,7 +14,7 @@ matrix:
   - go: tip
 
 env:
-- GO111MODULE=on GOLANGCI_RELEASE="v1.17.1"
+- GO111MODULE=on GOLANGCI_RELEASE="v1.16.0"
 
 before_install:
 - go get github.com/mattn/goveralls
diff --git a/Dockerfile b/Dockerfile
index 826ee450..7c8012a1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # builder image
-FROM golang:1.12.7 as builder
+FROM golang:1.12.6 as builder
 
 WORKDIR /github.com/kubernetes-incubator/external-dns
 COPY . .
diff --git a/Dockerfile.mini b/Dockerfile.mini
index 229aabc5..61bdcd03 100644
--- a/Dockerfile.mini
+++ b/Dockerfile.mini
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM golang:1.12.7 as builder
+FROM golang:1.12.6 as builder
 
 WORKDIR /github.com/kubernetes-incubator/external-dns
 COPY . .
diff --git a/README.md b/README.md
index 6284cdd0..2f34c9a9 100644
--- a/README.md
+++ b/README.md
@@ -105,37 +105,25 @@ The are two ways of running ExternalDNS:
 The following tutorials are provided:
 
 * [Alibaba Cloud](docs/tutorials/alibabacloud.md)
-* AWS
-	* [ALB Ingress Controller](docs/tutorials/alb-ingress.md)
-	* [Route53](docs/tutorials/aws.md)
-		* [Same domain for public and private Route53 zones](docs/tutorials/public-private-route53.md)
-	* [Service Discovery](docs/tutorials/aws-sd.md)
+* [AWS (Route53)](docs/tutorials/aws.md)
+* [AWS (Service Discovery)](docs/tutorials/aws-sd.md)
 * [Azure](docs/tutorials/azure.md)
-* [Cloudflare](docs/tutorials/cloudflare.md)
 * [CoreDNS](docs/tutorials/coredns.md)
+* [Cloudflare](docs/tutorials/cloudflare.md)
+* [RcodeZero](docs/tutorials/rcodezero.md)
 * [DigitalOcean](docs/tutorials/digitalocean.md)
-* [DNSimple](docs/tutorials/dnsimple.md)
+* [Infoblox](docs/tutorials/infoblox.md)
 * [Dyn](docs/tutorials/dyn.md)
-* [Exoscale](docs/tutorials/exoscale.md)
-* [ExternalName Services](docs/tutorials/externalname.md)
 * Google Container Engine
 	* [Using Google's Default Ingress Controller](docs/tutorials/gke.md)
 	* [Using the Nginx Ingress Controller](docs/tutorials/nginx-ingress.md)
-* [Headless Services](docs/tutorials/hostport.md)
-* [Infoblox](docs/tutorials/infoblox.md)
-* [Istio Gateway Source](docs/tutorials/istio.md)
-* [Kubernetes Security Context](docs/tutorials/security-context.md)
-* [Linode](docs/tutorials/linode.md)
-* [Nginx Ingress Controller](docs/tutorials/nginx-ingress.md)
-* [NS1](docs/tutorials/ns1.md)
-* [OpenStack Designate](docs/tutorials/designate.md)
+* [Exoscale](docs/tutorials/exoscale.md)
 * [Oracle Cloud Infrastructure (OCI) DNS](docs/tutorials/oracle.md)
-* [PowerDNS](docs/tutorials/pdns.md)
-* [RcodeZero](docs/tutorials/rcodezero.md)
-* [RancherDNS (RDNS)](docs/tutorials/rdns.md)
+* [Linode](docs/tutorials/linode.md)
 * [RFC2136](docs/tutorials/rfc2136.md)
+* [NS1](docs/tutorials/ns1.md)
 * [TransIP](docs/tutorials/transip.md)
-* [VinylDNS](docs/tutorials/vinyldns.md)
+* [RancherDNS](docs/tutorials/rdns.md)
 
 ### Running Locally
 
diff --git a/docs/contributing/sources-and-providers.md b/docs/contributing/sources-and-providers.md
index 4988cad9..37c9e116 100644
--- a/docs/contributing/sources-and-providers.md
+++ b/docs/contributing/sources-and-providers.md
@@ -22,7 +22,6 @@ All sources live in package `source`.
 * `ServiceSource`: collects all Services that have an external IP and returns them as Endpoint objects. The desired DNS name corresponds to an annotation set on the Service or is compiled from the Service attributes via the FQDN Go template string.
 * `IngressSource`: collects all Ingresses that have an external IP and returns them as Endpoint objects. The desired DNS name corresponds to the host rules defined in the Ingress object.
 * `IstioGatewaySource`: collects all Istio Gateways and returns them as Endpoint objects. The desired DNS name corresponds to the hosts listed within the servers spec of each Gateway object.
-* `ContourIngressRouteSource`: collects all Contour IngressRoutes and returns them as Endpoint objects. The desired DNS name corresponds to the `virtualhost.fqdn` listed within the spec of each IngressRoute object.
 * `FakeSource`: returns a random list of Endpoints for the purpose of testing providers without having access to a Kubernetes cluster.
 * `ConnectorSource`: returns a list of Endpoint objects which are served by a tcp server configured through `connector-source-server` flag.
 * `CRDSource`: returns a list of Endpoint objects sourced from the spec of CRD objects. For more details refer to [CRD source](../crd-source.md) documentation.
diff --git a/docs/faq.md b/docs/faq.md
index c4821b27..1c00adac 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -157,6 +157,19 @@ ExternalDNS can be configured to only use Services or Ingresses as source. In ca
 
 CNAMEs cannot co-exist with other records, therefore you can use the `--txt-prefix` flag which makes sure to create a TXT record with a name following the pattern `prefix.<CNAME record>`. For reference, see the issue https://github.com/kubernetes-incubator/external-dns/issues/262.
 
+### Can I force ExternalDNS to create CNAME records for ELB/ALB?
+
+The default logic is: when a target looks like an ELB/ALB, ExternalDNS will create ALIAS records for it.
+Under certain circumstances you want to force ExternalDNS to create CNAME records instead. If you want to do that, start ExternalDNS with the `--aws-prefer-cname` flag.
+
+Why should I want to force ExternalDNS to create CNAME records for ELB/ALB? Some motivations of users were:
+
+> "Our hosted zones records are synchronized with our enterprise DNS. The record type ALIAS is an AWS proprietary record type and AWS allows you to set a DNS record directly on AWS resources. Since this is not a DNS RfC standard and therefore can not be transferred and created in our enterprise DNS. So we need to force CNAME creation instead."
+
+or
+
+> "In case of ALIAS if we do nslookup with domain name, it will return only IPs of ELB. So it is always difficult for us to locate ELB in AWS console to which domain is pointing. If we configure it with CNAME it will return exact ELB CNAME, which is more helpful.!"
+
 ### Which permissions do I need when running ExternalDNS on a GCE or GKE node.
 
 You need to add either https://www.googleapis.com/auth/ndev.clouddns.readwrite or https://www.googleapis.com/auth/cloud-platform on your instance group's scope.
diff --git a/docs/tutorials/contour.md b/docs/tutorials/contour.md
deleted file mode 100644
index 1894bfc2..00000000
--- a/docs/tutorials/contour.md
+++ /dev/null
@@ -1,175 +0,0 @@
-# Configuring ExternalDNS to use the Contour IngressRoute Source
-This tutorial describes how to configure ExternalDNS to use the Contour IngressRoute source.
-It is meant to supplement the other provider-specific setup tutorials.
-
-### Manifest (for clusters without RBAC enabled)
-```yaml
-apiVersion: extensions/v1beta1
-kind: Deployment
-metadata:
-  name: external-dns
-spec:
-  strategy:
-    type: Recreate
-  template:
-    metadata:
-      labels:
-        app: external-dns
-    spec:
-      containers:
-      - name: external-dns
-        image: registry.opensource.zalan.do/teapot/external-dns:latest
-        args:
-        - --source=service
-        - --source=ingress
-        - --source=contour-ingressroute
-        - --contour-load-balancer=custom-contour-namespace/custom-contour-lb # load balancer service to be used. Omit to use the default (heptio-contour/contour)
-        - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
-        - --provider=aws
-        - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
-        - --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
-        - --registry=txt
-        - --txt-owner-id=my-identifier
-```
-
-### Manifest (for clusters with RBAC enabled)
-```yaml
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: external-dns
----
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRole
-metadata:
-  name: external-dns
-rules:
-- apiGroups: [""]
-  resources: ["services"]
-  verbs: ["get","watch","list"]
-- apiGroups: [""]
-  resources: ["pods"]
-  verbs: ["get","watch","list"]
-- apiGroups: ["extensions"] 
-  resources: ["ingresses"] 
-  verbs: ["get","watch","list"]
-- apiGroups: [""]
-  resources: ["nodes"]
-  verbs: ["list"]
-- apiGroups: ["contour.heptio.com"]
-  resources: ["ingressroutes"]
-  verbs: ["get","watch","list"]
----
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRoleBinding
-metadata:
-  name: external-dns-viewer
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: external-dns
-subjects:
-- kind: ServiceAccount
-  name: external-dns
-  namespace: default
----
-apiVersion: extensions/v1beta1
-kind: Deployment
-metadata:
-  name: external-dns
-spec:
-  strategy:
-    type: Recreate
-  template:
-    metadata:
-      labels:
-        app: external-dns
-    spec:
-      serviceAccountName: external-dns
-      containers:
-      - name: external-dns
-        image: registry.opensource.zalan.do/teapot/external-dns:latest
-        args:
-        - --source=service
-        - --source=ingress
-        - --source=contour-ingressroute
-        - --contour-load-balancer=custom-contour-namespace/custom-contour-lb # load balancer service to be used. Omit to use the default (heptio-contour/contour)
-        - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
-        - --provider=aws
-        - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
-        - --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
-        - --registry=txt
-        - --txt-owner-id=my-identifier
-```
-
-### Verify External DNS works (IngressRoute example)
-The following instructions are based on the 
-[Contour example workload](https://github.com/heptio/contour/blob/master/examples/example-workload/kuard-ingressroute.yaml).
-
-#### Install a sample service
-```bash
-$ kubectl apply -f - <<EOF
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  labels:
-    app: kuard
-  name: kuard
-spec:
-  replicas: 3
-  selector:
-    matchLabels:
-      app: kuard
-  template:
-    metadata:
-      labels:
-        app: kuard
-    spec:
-      containers:
-      - image: gcr.io/kuar-demo/kuard-amd64:1
-        name: kuard
----
-apiVersion: v1
-kind: Service
-metadata:
-  labels:
-    app: kuard
-  name: kuard
-spec:
-  ports:
-  - port: 80
-    protocol: TCP
-    targetPort: 8080
-  selector:
-    app: kuard
-  sessionAffinity: None
-  type: ClusterIP
----
-apiVersion: contour.heptio.com/v1beta1
-kind: IngressRoute
-metadata: 
-  labels:
-    app: kuard
-  name: kuard
-  namespace: default
-spec: 
-  virtualhost:
-    fqdn: kuard.example.com
-  routes: 
-  - match: /
-    services: 
-    - name: kuard
-      port: 80
-EOF
-```
-
-#### Access the sample service using `curl`
-```bash
-$ curl -i http://kuard.example.com/healthy
-HTTP/1.1 200 OK
-Content-Type: text/plain
-Date: Thu, 27 Jun 2019 19:42:26 GMT
-Content-Length: 2
-
-ok
-```
diff --git a/docs/tutorials/dnsimple.md b/docs/tutorials/dnsimple.md
deleted file mode 100644
index 1d43e7ff..00000000
--- a/docs/tutorials/dnsimple.md
+++ /dev/null
@@ -1,214 +0,0 @@
-# Setting up ExternalDNS for Services on DNSimple
-
-
-This tutorial describes how to setup ExternalDNS for usage with DNSimple.
-
-Make sure to use **>=0.4.6** version of ExternalDNS for this tutorial.
-
-## Created a DNSimple API Access Token
-
-A DNSimple API access token can be acquired by following the [provided documentation from DNSimple](https://support.dnsimple.com/articles/api-access-token/)
-
-The environment variable `DNSIMPLE_OAUTH` must be set to the API token generated for to run ExternalDNS with DNSimple.
-
-## Deploy ExternalDNS
-
-Connect your `kubectl` client to the cluster you want to test ExternalDNS with.
-Then apply one of the following manifests file to deploy ExternalDNS.
-
-### Manifest (for clusters without RBAC enabled)
-```yaml
-apiVersion: extensions/v1beta1
-kind: Deployment
-metadata:
-  name: external-dns
-spec:
-  strategy:
-    type: Recreate
-  template:
-    metadata:
-      labels:
-        app: external-dns
-    spec:
-      containers:
-      - name: external-dns
-        image: registry.opensource.zalan.do/teapot/external-dns:latest
-        args:
-        - --source=service
-        - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone you create in DNSimple.
-        - --provider=dnsimple
-        - --registry=txt
-        env:
-        - name: DNSIMPLE_OAUTH
-          value: "YOUR_DNSIMPLE_API_KEY"
-```
-
-### Manifest (for clusters with RBAC enabled)
-
-```yaml
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: external-dns
----
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRole
-metadata:
-  name: external-dns
-rules:
-- apiGroups: [""]
-  resources: ["services"]
-  verbs: ["get","watch","list"]
-- apiGroups: [""]
-  resources: ["pods"]
-  verbs: ["get","watch","list"]
-- apiGroups: ["extensions"]
-  resources: ["ingresses"]
-  verbs: ["get","watch","list"]
-- apiGroups: [""]
-  resources: ["nodes"]
-  verbs: ["list"]
----
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRoleBinding
-metadata:
-  name: external-dns-viewer
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: external-dns
-subjects:
-- kind: ServiceAccount
-  name: external-dns
-  namespace: default
----
-apiVersion: extensions/v1beta1
-kind: Deployment
-metadata:
-  name: external-dns
-spec:
-  strategy:
-    type: Recreate
-  template:
-    metadata:
-      labels:
-        app: external-dns
-    spec:
-      containers:
-      - name: external-dns
-        image: registry.opensource.zalan.do/teapot/external-dns:latest
-        args:
-        - --source=service
-        - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone you create in DNSimple.
-        - --provider=dnsimple
-        - --registry=txt
-        env:
-        - name: DNSIMPLE_OAUTH
-          value: "YOUR_DNSIMPLE_API_KEY"
-```
-
-
-## Deploying an Nginx Service
-
-Create a service file called 'nginx.yaml' with the following contents:
-
-```yaml
-apiVersion: extensions/v1beta1
-kind: Deployment
-metadata:
-  name: nginx
-spec:
-  template:
-    metadata:
-      labels:
-        app: nginx
-    spec:
-      containers:
-      - image: nginx
-        name: nginx
-        ports:
-        - containerPort: 80
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: nginx
-  annotations:
-    external-dns.alpha.kubernetes.io/hostname: validate-external-dns.example.com
-spec:
-  selector:
-    app: nginx
-  type: LoadBalancer
-  ports:
-    - protocol: TCP
-      port: 80
-      targetPort: 80
-```
-
-Note the annotation on the service; use the same hostname as the DNSimple DNS zone created above. The annotation may also be a subdomain
-of the DNS zone (e.g. 'www.example.com').
-
-ExternalDNS uses this annotation to determine what services should be registered with DNS.  Removing the annotation will cause ExternalDNS to remove the corresponding DNS records.
-
-Create the deployment and service:
-
-```sh
-$ kubectl create -f nginx.yaml
-```
-
-Depending where you run your service it can take a little while for your cloud provider to create an external IP for the service. Check the status by running
-`kubectl get services nginx`.  If the `EXTERNAL-IP` field shows an address, the service is ready to be accessed externally.
-
-Once the service has an external IP assigned, ExternalDNS will notice the new service IP address and synchronize
-the DNSimple DNS records.
-
-## Verifying DNSimple DNS records
-
-### Getting your DNSimple Account ID
-
-If you do not know your DNSimple account ID it can be aquired using the [whoami](https://developer.dnsimple.com/v2/identity/#whoami) endpoint from the DNSimple Identity API
-
-```sh
-curl -H "Authorization: Bearer $DNSIMPLE_ACCOUNT_TOKEN" \
-    -H 'Accept: application/json' \
-    https://api.dnsimple.com/v2/whoami
-{
-  "data": {
-    "user": null,
-    "account": {
-      "id": 1,
-      "email": "example-account@example.com",
-      "plan_identifier": "dnsimple-professional",
-      "created_at": "2015-09-18T23:04:37Z",
-      "updated_at": "2016-06-09T20:03:39Z"
-    }
-  }
-}
-```
-
-### Looking at the DNSimple Dashboard
-
-You can view your DNSimple Record Editor at https://dnsimple.com/a/YOUR_ACCOUNT_ID/domains/example.com/records. Ensure you substitute the value `YOUR_ACCOUNT_ID` with the ID of your DNSimple account and `example.com` with the correct domain that you used during validation.
-
-### Using the DNSimple Zone Records API
-
-This approach allows for you to use the DNSimple [List records for a zone](https://developer.dnsimple.com/v2/zones/records/#listZoneRecords) endpoint to verify the creation of the A and TXT record. Ensure you substitute the value `YOUR_ACCOUNT_ID` with the ID of your DNSimple account and `example.com` with the correct domain that you used during validation.
-
-```sh
-curl -H "Authorization: Bearer $DNSIMPLE_ACCOUNT_TOKEN" \
-    -H 'Accept: application/json' \
-    'https://api.dnsimple.com/v2/YOUR_ACCOUNT_ID/zones/example.com/records&name=validate-external-dns'
-```
-
-## Clean up
-
-Now that we have verified that ExternalDNS will automatically manage DNSimple DNS records, we can delete the tutorial's example:
-
-```sh
-$ kubectl delete -f nginx.yaml
-$ kubectl delete -f externaldns.yaml
-```
-
-### Deleting Created Records
-
-The created records can be deleted using the record IDs from the verification step and the [Delete a zone record](https://developer.dnsimple.com/v2/zones/records/#deleteZoneRecord) endpoint.
diff --git a/go.mod b/go.mod
index f522ea63..4e7a7b05 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/kubernetes-incubator/external-dns
 go 1.12
 
 require (
-	cloud.google.com/go v0.37.4
+	cloud.google.com/go v0.34.0
 	github.com/Azure/azure-sdk-for-go v10.0.4-beta+incompatible
 	github.com/Azure/go-autorest v10.9.0+incompatible
 	github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 // indirect
@@ -25,10 +25,17 @@ require (
 	github.com/digitalocean/godo v1.1.1
 	github.com/dnaeon/go-vcr v1.0.1 // indirect
 	github.com/dnsimple/dnsimple-go v0.14.0
+	github.com/envoyproxy/go-control-plane v0.6.9 // indirect
 	github.com/exoscale/egoscale v0.11.0
 	github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99
 	github.com/go-resty/resty v1.8.0 // indirect
+	github.com/gogo/googleapis v1.1.0 // indirect
+	github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect
+	github.com/golang/mock v1.2.0 // indirect
+	github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a // indirect
 	github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
+	github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
+	github.com/googleapis/gnostic v0.2.0 // indirect
 	github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8
 	github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c // indirect
 	github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
@@ -36,7 +43,7 @@ require (
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
 	github.com/grpc-ecosystem/grpc-gateway v1.8.5 // indirect
 	github.com/hashicorp/go-multierror v1.0.0 // indirect
-	github.com/heptio/contour v0.13.0
+	github.com/imdario/mergo v0.3.5 // indirect
 	github.com/inconshreveable/mousetrap v1.0.0 // indirect
 	github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65
 	github.com/jonboulle/clockwork v0.1.0 // indirect
@@ -47,6 +54,7 @@ require (
 	github.com/mattn/go-isatty v0.0.7 // indirect
 	github.com/miekg/dns v1.0.8
 	github.com/mitchellh/mapstructure v1.1.2 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.1 // indirect
 	github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
 	github.com/nesv/go-dynect v0.6.0
@@ -54,16 +62,18 @@ require (
 	github.com/onsi/ginkgo v1.8.0 // indirect
 	github.com/onsi/gomega v1.5.0 // indirect
 	github.com/oracle/oci-go-sdk v1.8.0
+	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
 	github.com/pkg/errors v0.8.1
 	github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829
 	github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0
 	github.com/satori/go.uuid v1.2.0 // indirect
 	github.com/sergi/go-diff v1.0.0 // indirect
-	github.com/sirupsen/logrus v1.4.1
+	github.com/sirupsen/logrus v1.2.0
 	github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
 	github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
 	github.com/soheilhy/cmux v0.1.3 // indirect
 	github.com/spf13/cobra v0.0.3 // indirect
+	github.com/spf13/pflag v1.0.2 // indirect
 	github.com/stretchr/testify v1.2.2
 	github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9 // indirect
 	github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 // indirect
@@ -76,18 +86,19 @@ require (
 	go.uber.org/atomic v1.3.2 // indirect
 	go.uber.org/multierr v1.1.0 // indirect
 	go.uber.org/zap v1.9.1 // indirect
-	golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c
-	golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a
-	google.golang.org/api v0.3.1
+	golang.org/x/net v0.0.0-20190311183353-d8887717615a
+	golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421
+	google.golang.org/api v0.3.0
 	google.golang.org/appengine v1.5.0 // indirect
+	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
 	gopkg.in/ns1/ns1-go.v2 v2.0.0-20190322154155-0dafb5275fd1
 	gopkg.in/yaml.v2 v2.2.2
 	istio.io/api v0.0.0-20190321180614-db16d82d3672
 	istio.io/istio v0.0.0-20190322063008-2b1331886076
-	k8s.io/api v0.0.0-20190503184017-f1b257a4ce96
-	k8s.io/apiextensions-apiserver v0.0.0-20190503184539-c338b28ceaa1
-	k8s.io/apimachinery v0.0.0-20190223001710-c182ff3b9841
+	k8s.io/api v0.0.0-20180628040859-072894a440bd
+	k8s.io/apiextensions-apiserver v0.0.0-20180628053655-3de98c57bc05 // indirect
+	k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d
 	k8s.io/client-go v8.0.0+incompatible
 	k8s.io/kube-openapi v0.0.0-20190401085232-94e1e7b7574c // indirect
 	launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
diff --git a/go.sum b/go.sum
index 4f721f29..405476f3 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,6 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
-cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
 code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTgeiff9vxdrfdqxibzpWjxLnuXDI5m6z3GJAk=
 code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI=
 git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
@@ -72,11 +70,6 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
 github.com/envoyproxy/go-control-plane v0.6.9 h1:deEH9W8ZAUGNbCdX+9iNzBOGrAOrnpJGoy0PcTqk/tE=
 github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
-github.com/envoyproxy/go-control-plane v0.8.0 h1:uE6Fp4fOcAJdc1wTQXLJ+SYistkbG1dNoi6Zs1+Ybvk=
-github.com/envoyproxy/go-control-plane v0.8.0/go.mod h1:GSSbY9P1neVhdY7G4wu+IK1rk/dqhiCC/4ExuWJZVuk=
-github.com/envoyproxy/protoc-gen-validate v0.0.14 h1:YBW6/cKy9prEGRYLnaGa4IDhzxZhRCtKsax8srGKDnM=
-github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/exoscale/egoscale v0.11.0 h1:g+UBsxLDouKWW2BK/UTgQFAVnM2aHygheF0Dxj0ycC8=
 github.com/exoscale/egoscale v0.11.0/go.mod h1:Ee3U4ZjSDpbbEc9VkQ/jttUU8USE8Nv7L3YzVi03Y1U=
 github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 h1:jmwW6QWvUO2OPe22YfgFvBaaZlSr8Rlrac5lZvG6IdM=
@@ -97,8 +90,6 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
 github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
@@ -109,17 +100,12 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a h1:ZJu5NB1Bk5ms4vw0Xu4i+jD32SE9jQXyfnOvwhHqlT0=
 github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0=
 github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
 github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
 github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
 github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
 github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8 h1:L9JPKrtsHMQ4VCRQfHvbbHBfB2Urn8xf6QZeXZ+OrN4=
@@ -127,14 +113,12 @@ github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:
 github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
 github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
 github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c h1:Lh2aW+HnU2Nbe1gqD9SOJLJxW1jBMmQOktN2acDyJk8=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q=
 github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79 h1:lR9ssWAqp9qL0bALxqEEkuudiP1eweOdv9jsRK3e7lE=
@@ -150,16 +134,10 @@ github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uP
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
 github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/heptio/contour v0.13.0 h1:kiJ7qC439vFD21DTyQPNPzOGfDqkO/y//GrLYWJ5MdY=
-github.com/heptio/contour v0.13.0/go.mod h1:qYE0FAuA8W1NJEaHmyOoWkJZTRPL1x4GVO5BGZMG1Os=
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
-github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65 h1:FP5rOFP4ifbtFIjFHJmwhFrsbDyONILK/FNntl/Pou8=
@@ -168,16 +146,12 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5i
 github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
 github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
-github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -202,14 +176,12 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
 github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/mdempsky/unconvert v0.0.0-20190325185700-2f5dc3378ed3/go.mod h1:9+3Wp2ccIz73BJqVfc7n2+1A+mzvnEwtDTqEjeRngBQ=
 github.com/miekg/dns v1.0.8 h1:Zi8HNpze3NeRWH1PQV6O71YcvJRQ6j0lORO6DAEmAAI=
 github.com/miekg/dns v1.0.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -248,18 +220,13 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
 github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
 github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190403104016-ea9eea638872 h1:0aNv3xC7DmQoy1/x1sMh18g+fihWW68LL13i8ao9kl4=
-github.com/prometheus/procfs v0.0.0-20190403104016-ea9eea638872/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/go-internal v1.2.1/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 h1:vOcHdR1nu7DO4BAx1rwzdHV7jQTzW3gqcBT5qxHSc6A=
 github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0/go.mod h1:FeplEtXXejBYC4NPAFTrs5L7KuK+5RL9bf5nB2vZe9o=
 github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
@@ -268,8 +235,6 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
-github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@@ -284,8 +249,6 @@ github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=
 github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
@@ -311,8 +274,6 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A=
 go.opencensus.io v0.19.2 h1:ZZpq6xI6kv/LuE/5s5UQvBU5vMjvRnPb8PvJrIntAnc=
 go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M=
-go.opencensus.io v0.20.1 h1:pMEjRZ1M4ebWGikflH7nQpV6+Zr88KBMA2XJD3sbijw=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
@@ -322,8 +283,6 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5 h1:bselrhR0Or1vomJZC8ZIjWtbDmn9OYFLX5Ik9alpJpE=
-golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -343,22 +302,17 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -369,35 +323,20 @@ golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190508220229-2d0786266e9c h1:hDn6jm7snBX2O7+EeTk6Q4WXJfKt7MWgtiCCRi1rBoY=
-golang.org/x/sys v0.0.0-20190508220229-2d0786266e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190213192042-740235f6c0d8/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190325161752-5a8dccf5b48a/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
 google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU=
 google.golang.org/api v0.3.0 h1:UIJY20OEo3+tK5MBlcdx37kmdH6EnRjGkW78mc6+EeA=
 google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw=
-google.golang.org/api v0.3.1 h1:oJra/lMfmtm13/rgY/8i3MzjFWYXvQIAKjQ3HqofMk8=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -407,19 +346,14 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
 google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 h1:xtNn7qFlagY2mQNFHMSRPjT2RkOV4OXM7P5TVy9xATo=
-google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.19.1 h1:TrBcJ1yqAl1G++wO39nD/qtgpsW9/1+QGrluyMGEYgM=
-google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
@@ -439,38 +373,19 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 istio.io/api v0.0.0-20190321180614-db16d82d3672 h1:luY97pBVarSo1v++zf2kgb84Q55G5hv/ult2A4KPQuk=
 istio.io/api v0.0.0-20190321180614-db16d82d3672/go.mod h1:hhLFQmpHia8zgaM37vb2ml9iS5NfNfqZGRt1pS9aVEo=
-istio.io/gogo-genproto v0.0.0-20190124151557-6d926a6e6feb/go.mod h1:eIDJ6jNk/IeJz6ODSksHl5Aiczy5JUq6vFhJWI5OtiI=
 istio.io/istio v0.0.0-20190322063008-2b1331886076 h1:gZhCrmVzfQJoDl4oav8i5+NF7p7v0M1Pou+2O+hZBtc=
 istio.io/istio v0.0.0-20190322063008-2b1331886076/go.mod h1:OWBySrQjjk549IhxWCt7DTl9ZSsXdvbgm+SmgGVRsGA=
 k8s.io/api v0.0.0-20180628040859-072894a440bd h1:HzgYeLDS1jLxw8DGr68KJh9cdQ5iZJizG0HZWstIhfQ=
 k8s.io/api v0.0.0-20180628040859-072894a440bd/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
-k8s.io/api v0.0.0-20190226173710-145d52631d00 h1:xYfyMq0qxTGAg3O9GK23GMbNrBcpnFg9IeA6isDgIXk=
-k8s.io/api v0.0.0-20190226173710-145d52631d00/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
-k8s.io/api v0.0.0-20190503184017-f1b257a4ce96 h1:zq/7PZXqJ6ZbPfLRbIm9Qs6gHMviY72SPk4ugPUPDvI=
-k8s.io/api v0.0.0-20190503184017-f1b257a4ce96/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
 k8s.io/apiextensions-apiserver v0.0.0-20180628053655-3de98c57bc05 h1:uKDX+1GgQuV/J6TTgrtHYGRFZUPWxC13mJwBhjIhm/w=
 k8s.io/apiextensions-apiserver v0.0.0-20180628053655-3de98c57bc05/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE=
-k8s.io/apiextensions-apiserver v0.0.0-20190503184539-c338b28ceaa1 h1:uNrdMFGXgDAaw+WyJSuRhnzW2eZkqZjc04SZOr4wky8=
-k8s.io/apiextensions-apiserver v0.0.0-20190503184539-c338b28ceaa1/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE=
 k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d h1:MZjlsu9igBoVPZkXpIGoxI6EonqNsXXZU7hhvfQLkd4=
 k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
-k8s.io/apimachinery v0.0.0-20190221084156-01f179d85dbc h1:7z9/6jKWBqkK9GI1RRB0B5fZcmkatLQ/nv8kysch24o=
-k8s.io/apimachinery v0.0.0-20190221084156-01f179d85dbc/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
-k8s.io/apimachinery v0.0.0-20190223001710-c182ff3b9841 h1:Q4RZrHNtlC/mSdC1sTrcZ5RchC/9vxLVj57pWiCBKv4=
-k8s.io/apimachinery v0.0.0-20190223001710-c182ff3b9841/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
-k8s.io/client-go v0.0.0-20190226174127-78295b709ec6/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
 k8s.io/client-go v8.0.0+incompatible h1:tTI4hRmb1DRMl4fG6Vclfdi6nTM82oIrTT7HfitmxC4=
 k8s.io/client-go v8.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
-k8s.io/code-generator v0.0.0-20190409092313-b1289fc74931/go.mod h1:MYiN+ZJZ9HkETbgVZdWw2AsuAi9PZ4V80cwfuf2axe8=
-k8s.io/gengo v0.0.0-20190116091435-f8a0810f38af/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/klog v0.0.0-20190306015804-8e90cee79f82/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/kube-openapi v0.0.0-20190115222348-ced9eb3070a5/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
 k8s.io/kube-openapi v0.0.0-20190401085232-94e1e7b7574c h1:kJCzg2vGCzah5icgkKR7O1Dzn0NA2iGlym27sb0ZfGE=
 k8s.io/kube-openapi v0.0.0-20190401085232-94e1e7b7574c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
 launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
 launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
-mvdan.cc/unparam v0.0.0-20190310220240-1b9ccfa71afe/go.mod h1:BnhuWBAqxH3+J5bDybdxgw5ZfS+DsVd4iylsKQePN8o=
diff --git a/main.go b/main.go
index a7da2045..e5f2eb25 100644
--- a/main.go
+++ b/main.go
@@ -85,7 +85,6 @@ func main() {
 		CFAPIEndpoint:               cfg.CFAPIEndpoint,
 		CFUsername:                  cfg.CFUsername,
 		CFPassword:                  cfg.CFPassword,
-		ContourLoadBalancerService:  cfg.ContourLoadBalancerService,
 	}
 
 	// Lookup all the selected sources by names and pass them the desired configuration.
@@ -178,7 +177,7 @@ func main() {
 			},
 		)
 	case "coredns", "skydns":
-		p, err = provider.NewCoreDNSProvider(domainFilter, cfg.CoreDNSPrefix, cfg.DryRun)
+		p, err = provider.NewCoreDNSProvider(domainFilter, cfg.DryRun)
 	case "rdns":
 		p, err = provider.NewRDNSProvider(
 			provider.RDNSConfig{
diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go
index bf7a99ba..0d40a615 100644
--- a/pkg/apis/externaldns/types.go
+++ b/pkg/apis/externaldns/types.go
@@ -41,7 +41,6 @@ type Config struct {
 	KubeConfig                  string
 	RequestTimeout              time.Duration
 	IstioIngressGatewayServices []string
-	ContourLoadBalancerService  string
 	Sources                     []string
 	Namespace                   string
 	AnnotationFilter            string
@@ -71,7 +70,6 @@ type Config struct {
 	AzureResourceGroup          string
 	CloudflareProxied           bool
 	CloudflareZonesPerPage      int
-	CoreDNSPrefix               string
 	RcodezeroTXTEncrypt         bool
 	InfobloxGridHost            string
 	InfobloxWapiPort            int
@@ -132,7 +130,6 @@ var defaultConfig = &Config{
 	KubeConfig:                  "",
 	RequestTimeout:              time.Second * 30,
 	IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway"},
-	ContourLoadBalancerService:  "heptio-contour/contour",
 	Sources:                     nil,
 	Namespace:                   "",
 	AnnotationFilter:            "",
@@ -160,7 +157,6 @@ var defaultConfig = &Config{
 	AzureResourceGroup:          "",
 	CloudflareProxied:           false,
 	CloudflareZonesPerPage:      50,
-	CoreDNSPrefix:               "/skydns/",
 	RcodezeroTXTEncrypt:         false,
 	InfobloxGridHost:            "",
 	InfobloxWapiPort:            443,
@@ -266,11 +262,8 @@ func (cfg *Config) ParseFlags(args []string) error {
 	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 Contour
-	app.Flag("contour-load-balancer", "The fully-qualified name of the Contour load balancer service. (default: heptio-contour/contour)").Default("heptio-contour/contour").StringVar(&cfg.ContourLoadBalancerService)
-
 	// 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, cloudfoundry, contour-ingressroute, crd, empty").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "istio-gateway", "cloudfoundry", "contour-ingressroute", "fake", "connector", "crd", "empty")
+	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, cloudfoundry, crd, empty").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "istio-gateway", "cloudfoundry", "fake", "connector", "crd", "empty")
 	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)
@@ -304,7 +297,6 @@ func (cfg *Config) ParseFlags(args []string) error {
 	app.Flag("azure-resource-group", "When using the Azure provider, override the Azure resource group to use (optional)").Default(defaultConfig.AzureResourceGroup).StringVar(&cfg.AzureResourceGroup)
 	app.Flag("cloudflare-proxied", "When using the Cloudflare provider, specify if the proxy mode must be enabled (default: disabled)").BoolVar(&cfg.CloudflareProxied)
 	app.Flag("cloudflare-zones-per-page", "When using the Cloudflare provider, specify how many zones per page listed, max. possible 50 (default: 50)").Default(strconv.Itoa(defaultConfig.CloudflareZonesPerPage)).IntVar(&cfg.CloudflareZonesPerPage)
-	app.Flag("coredns-prefix", "When using the CoreDNS provider, specify the prefix name").Default(defaultConfig.CoreDNSPrefix).StringVar(&cfg.CoreDNSPrefix)
 	app.Flag("infoblox-grid-host", "When using the Infoblox provider, specify the Grid Manager host (required when --provider=infoblox)").Default(defaultConfig.InfobloxGridHost).StringVar(&cfg.InfobloxGridHost)
 	app.Flag("infoblox-wapi-port", "When using the Infoblox provider, specify the WAPI port (default: 443)").Default(strconv.Itoa(defaultConfig.InfobloxWapiPort)).IntVar(&cfg.InfobloxWapiPort)
 	app.Flag("infoblox-wapi-username", "When using the Infoblox provider, specify the WAPI username (default: admin)").Default(defaultConfig.InfobloxWapiUsername).StringVar(&cfg.InfobloxWapiUsername)
@@ -319,6 +311,7 @@ func (cfg *Config) ParseFlags(args []string) error {
 	app.Flag("dyn-min-ttl", "Minimal TTL (in seconds) for records. This value will be used if the provided TTL for a service/ingress is lower than this.").IntVar(&cfg.DynMinTTLSeconds)
 	app.Flag("oci-config-file", "When using the OCI provider, specify the OCI configuration file (required when --provider=oci").Default(defaultConfig.OCIConfigFile).StringVar(&cfg.OCIConfigFile)
 	app.Flag("rcodezero-txt-encrypt", "When using the Rcodezero provider with txt registry option, set if TXT rrs are encrypted (default: false)").Default(strconv.FormatBool(defaultConfig.RcodezeroTXTEncrypt)).BoolVar(&cfg.RcodezeroTXTEncrypt)
+
 	app.Flag("inmemory-zone", "Provide a list of pre-configured zones for the inmemory provider; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.InMemoryZones)
 	app.Flag("pdns-server", "When using the PowerDNS/PDNS provider, specify the URL to the pdns server (required when --provider=pdns)").Default(defaultConfig.PDNSServer).StringVar(&cfg.PDNSServer)
 	app.Flag("pdns-api-key", "When using the PowerDNS/PDNS provider, specify the API key to use to authorize requests (required when --provider=pdns)").Default(defaultConfig.PDNSAPIKey).StringVar(&cfg.PDNSAPIKey)
diff --git a/provider/coredns.go b/provider/coredns.go
index 019003ce..bd09f40a 100644
--- a/provider/coredns.go
+++ b/provider/coredns.go
@@ -45,6 +45,8 @@ const (
 	priority    = 10 // default priority when nothing is set
 	etcdTimeout = 5 * time.Second
 
+	coreDNSPrefix = "/skydns/"
+
 	randomPrefixLabel = "prefix"
 )
 
@@ -56,10 +58,9 @@ type coreDNSClient interface {
 }
 
 type coreDNSProvider struct {
-	dryRun        bool
-	coreDNSPrefix string
-	domainFilter  DomainFilter
-	client        coreDNSClient
+	dryRun       bool
+	domainFilter DomainFilter
+	client       coreDNSClient
 }
 
 // Service represents CoreDNS etcd record
@@ -244,17 +245,15 @@ func newETCDClient() (coreDNSClient, error) {
 }
 
 // NewCoreDNSProvider is a CoreDNS provider constructor
-func NewCoreDNSProvider(domainFilter DomainFilter, prefix string, dryRun bool) (Provider, error) {
+func NewCoreDNSProvider(domainFilter DomainFilter, dryRun bool) (Provider, error) {
 	client, err := newETCDClient()
 	if err != nil {
 		return nil, err
 	}
-
 	return coreDNSProvider{
-		client:        client,
-		dryRun:        dryRun,
-		coreDNSPrefix: prefix,
-		domainFilter:  domainFilter,
+		client:       client,
+		dryRun:       dryRun,
+		domainFilter: domainFilter,
 	}, nil
 }
 
@@ -262,12 +261,12 @@ func NewCoreDNSProvider(domainFilter DomainFilter, prefix string, dryRun bool) (
 // it may be mapped to one or two records of type A, CNAME, TXT, A+TXT, CNAME+TXT
 func (p coreDNSProvider) Records() ([]*endpoint.Endpoint, error) {
 	var result []*endpoint.Endpoint
-	services, err := p.client.GetServices(p.coreDNSPrefix)
+	services, err := p.client.GetServices(coreDNSPrefix)
 	if err != nil {
 		return nil, err
 	}
 	for _, service := range services {
-		domains := strings.Split(strings.TrimPrefix(service.Key, p.coreDNSPrefix), "/")
+		domains := strings.Split(strings.TrimPrefix(service.Key, coreDNSPrefix), "/")
 		reverse(domains)
 		dnsName := strings.Join(domains[service.TargetStrip:], ".")
 		if !p.domainFilter.Match(dnsName) {
@@ -328,7 +327,7 @@ func (p coreDNSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
 				service := Service{
 					Host:        target,
 					Text:        ep.Labels["originalText"],
-					Key:         p.etcdKeyFor(prefix + "." + dnsName),
+					Key:         etcdKeyFor(prefix + "." + dnsName),
 					TargetStrip: strings.Count(prefix, ".") + 1,
 					TTL:         uint32(ep.RecordTTL),
 				}
@@ -346,7 +345,7 @@ func (p coreDNSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
 					prefix = fmt.Sprintf("%08x", rand.Int31())
 				}
 				services = append(services, Service{
-					Key:         p.etcdKeyFor(prefix + "." + dnsName),
+					Key:         etcdKeyFor(prefix + "." + dnsName),
 					TargetStrip: strings.Count(prefix, ".") + 1,
 					TTL:         uint32(ep.RecordTTL),
 				})
@@ -375,7 +374,7 @@ func (p coreDNSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
 		if ep.Labels[randomPrefixLabel] != "" {
 			dnsName = ep.Labels[randomPrefixLabel] + "." + dnsName
 		}
-		key := p.etcdKeyFor(dnsName)
+		key := etcdKeyFor(dnsName)
 		log.Infof("Delete key %s", key)
 		if !p.dryRun {
 			err := p.client.DeleteService(key)
@@ -388,12 +387,6 @@ func (p coreDNSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
 	return nil
 }
 
-func (p coreDNSProvider) etcdKeyFor(dnsName string) string {
-	domains := strings.Split(dnsName, ".")
-	reverse(domains)
-	return p.coreDNSPrefix + strings.Join(domains, "/")
-}
-
 func guessRecordType(target string) string {
 	if net.ParseIP(target) != nil {
 		return endpoint.RecordTypeA
@@ -401,6 +394,12 @@ func guessRecordType(target string) string {
 	return endpoint.RecordTypeCNAME
 }
 
+func etcdKeyFor(dnsName string) string {
+	domains := strings.Split(dnsName, ".")
+	reverse(domains)
+	return coreDNSPrefix + strings.Join(domains, "/")
+}
+
 func reverse(slice []string) {
 	for i := 0; i < len(slice)/2; i++ {
 		j := len(slice) - i - 1
diff --git a/source/ingressroute.go b/source/ingressroute.go
deleted file mode 100644
index 036846ef..00000000
--- a/source/ingressroute.go
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
-Copyright 2017 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 (
-	"bytes"
-	"fmt"
-	"sort"
-	"strings"
-	"text/template"
-	"time"
-
-	contourapi "github.com/heptio/contour/apis/contour/v1beta1"
-	contour "github.com/heptio/contour/apis/generated/clientset/versioned"
-	contourinformers "github.com/heptio/contour/apis/generated/informers/externalversions"
-	extinformers "github.com/heptio/contour/apis/generated/informers/externalversions/contour/v1beta1"
-	"github.com/kubernetes-incubator/external-dns/endpoint"
-	"github.com/pkg/errors"
-	log "github.com/sirupsen/logrus"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/apimachinery/pkg/util/wait"
-	"k8s.io/client-go/kubernetes"
-	"k8s.io/client-go/tools/cache"
-)
-
-// ingressRouteSource is an implementation of Source for Heptio Contour IngressRoute objects.
-// The IngressRoute implementation uses the spec.virtualHost.fqdn value for the hostname.
-// Use targetAnnotationKey to explicitly set Endpoint.
-type ingressRouteSource struct {
-	kubeClient                 kubernetes.Interface
-	contourClient              contour.Interface
-	contourLoadBalancerService string
-	namespace                  string
-	annotationFilter           string
-	fqdnTemplate               *template.Template
-	combineFQDNAnnotation      bool
-	ignoreHostnameAnnotation   bool
-	ingressRouteInformer       extinformers.IngressRouteInformer
-}
-
-// NewIngressRouteSource creates a new ingressRouteSource with the given config.
-func NewContourIngressRouteSource(
-	kubeClient kubernetes.Interface,
-	contourClient contour.Interface,
-	contourLoadBalancerService string,
-	namespace string,
-	annotationFilter string,
-	fqdnTemplate string,
-	combineFqdnAnnotation bool,
-	ignoreHostnameAnnotation bool,
-) (Source, error) {
-	var (
-		tmpl *template.Template
-		err  error
-	)
-	if fqdnTemplate != "" {
-		tmpl, err = template.New("endpoint").Funcs(template.FuncMap{
-			"trimPrefix": strings.TrimPrefix,
-		}).Parse(fqdnTemplate)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	if _, _, err = parseContourLoadBalancerService(contourLoadBalancerService); err != nil {
-		return nil, err
-	}
-
-	// Use shared informer to listen for add/update/delete of ingressroutes in the specified namespace.
-	// Set resync period to 0, to prevent processing when nothing has changed.
-	informerFactory := contourinformers.NewSharedInformerFactoryWithOptions(
-		contourClient,
-		0,
-		contourinformers.WithNamespace(namespace),
-	)
-	ingressRouteInformer := informerFactory.Contour().V1beta1().IngressRoutes()
-
-	// Add default resource event handlers to properly initialize informer.
-	ingressRouteInformer.Informer().AddEventHandler(
-		cache.ResourceEventHandlerFuncs{
-			AddFunc: func(obj interface{}) {
-			},
-		},
-	)
-
-	// TODO informer is not explicitly stopped since controller is not passing in its channel.
-	informerFactory.Start(wait.NeverStop)
-
-	// wait for the local cache to be populated.
-	err = wait.Poll(time.Second, 60*time.Second, func() (bool, error) {
-		return ingressRouteInformer.Informer().HasSynced() == true, nil
-	})
-	if err != nil {
-		return nil, fmt.Errorf("failed to sync cache: %v", err)
-	}
-
-	return &ingressRouteSource{
-		kubeClient:                 kubeClient,
-		contourClient:              contourClient,
-		contourLoadBalancerService: contourLoadBalancerService,
-		namespace:                  namespace,
-		annotationFilter:           annotationFilter,
-		fqdnTemplate:               tmpl,
-		combineFQDNAnnotation:      combineFqdnAnnotation,
-		ignoreHostnameAnnotation:   ignoreHostnameAnnotation,
-		ingressRouteInformer:       ingressRouteInformer,
-	}, nil
-}
-
-// Endpoints returns endpoint objects for each host-target combination that should be processed.
-// Retrieves all ingressroute resources in the source's namespace(s).
-func (sc *ingressRouteSource) Endpoints() ([]*endpoint.Endpoint, error) {
-	irs, err := sc.ingressRouteInformer.Lister().IngressRoutes(sc.namespace).List(labels.Everything())
-	if err != nil {
-		return nil, err
-	}
-
-	irs, err = sc.filterByAnnotations(irs)
-	if err != nil {
-		return nil, err
-	}
-
-	endpoints := []*endpoint.Endpoint{}
-
-	for _, ir := range irs {
-		// Check controller annotation to see if we are responsible.
-		controller, ok := ir.Annotations[controllerAnnotationKey]
-		if ok && controller != controllerAnnotationValue {
-			log.Debugf("Skipping ingressroute %s/%s because controller value does not match, found: %s, required: %s",
-				ir.Namespace, ir.Name, controller, controllerAnnotationValue)
-			continue
-		} else if ir.CurrentStatus != "valid" {
-			log.Debugf("Skipping ingressroute %s/%s because it is not valid", ir.Namespace, ir.Name)
-			continue
-		}
-
-		irEndpoints, err := sc.endpointsFromIngressRoute(ir)
-		if err != nil {
-			return nil, err
-		}
-
-		// apply template if fqdn is missing on ingressroute
-		if (sc.combineFQDNAnnotation || len(irEndpoints) == 0) && sc.fqdnTemplate != nil {
-			tmplEndpoints, err := sc.endpointsFromTemplate(ir)
-			if err != nil {
-				return nil, err
-			}
-
-			if sc.combineFQDNAnnotation {
-				irEndpoints = append(irEndpoints, tmplEndpoints...)
-			} else {
-				irEndpoints = tmplEndpoints
-			}
-		}
-
-		if len(irEndpoints) == 0 {
-			log.Debugf("No endpoints could be generated from ingressroute %s/%s", ir.Namespace, ir.Name)
-			continue
-		}
-
-		log.Debugf("Endpoints generated from ingressroute: %s/%s: %v", ir.Namespace, ir.Name, irEndpoints)
-		sc.setResourceLabel(ir, irEndpoints)
-		endpoints = append(endpoints, irEndpoints...)
-	}
-
-	for _, ep := range endpoints {
-		sort.Sort(ep.Targets)
-	}
-
-	return endpoints, nil
-}
-
-func (sc *ingressRouteSource) endpointsFromTemplate(ingressRoute *contourapi.IngressRoute) ([]*endpoint.Endpoint, error) {
-	// Process the whole template string
-	var buf bytes.Buffer
-	err := sc.fqdnTemplate.Execute(&buf, ingressRoute)
-	if err != nil {
-		return nil, fmt.Errorf("failed to apply template on ingressroute %s/%s: %v", ingressRoute.Namespace, ingressRoute.Name, err)
-	}
-
-	hostnames := buf.String()
-
-	ttl, err := getTTLFromAnnotations(ingressRoute.Annotations)
-	if err != nil {
-		log.Warn(err)
-	}
-
-	targets := getTargetsFromTargetAnnotation(ingressRoute.Annotations)
-
-	if len(targets) == 0 {
-		targets, err = sc.targetsFromContourLoadBalancer()
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	providerSpecific := getProviderSpecificAnnotations(ingressRoute.Annotations)
-
-	var endpoints []*endpoint.Endpoint
-	// splits the FQDN template and removes the trailing periods
-	hostnameList := strings.Split(strings.Replace(hostnames, " ", "", -1), ",")
-	for _, hostname := range hostnameList {
-		hostname = strings.TrimSuffix(hostname, ".")
-		endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific)...)
-	}
-	return endpoints, nil
-}
-
-// filterByAnnotations filters a list of configs by a given annotation selector.
-func (sc *ingressRouteSource) filterByAnnotations(ingressRoutes []*contourapi.IngressRoute) ([]*contourapi.IngressRoute, error) {
-	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
-	if selector.Empty() {
-		return ingressRoutes, nil
-	}
-
-	filteredList := []*contourapi.IngressRoute{}
-
-	for _, ingressRoute := range ingressRoutes {
-		// convert the ingressroute's annotations to an equivalent label selector
-		annotations := labels.Set(ingressRoute.Annotations)
-
-		// include ingressroute if its annotations match the selector
-		if selector.Matches(annotations) {
-			filteredList = append(filteredList, ingressRoute)
-		}
-	}
-
-	return filteredList, nil
-}
-
-func (sc *ingressRouteSource) setResourceLabel(ingressRoute *contourapi.IngressRoute, endpoints []*endpoint.Endpoint) {
-	for _, ep := range endpoints {
-		ep.Labels[endpoint.ResourceLabelKey] = fmt.Sprintf("ingressroute/%s/%s", ingressRoute.Namespace, ingressRoute.Name)
-	}
-}
-
-func (sc *ingressRouteSource) targetsFromContourLoadBalancer() (targets endpoint.Targets, err error) {
-	lbNamespace, lbName, err := parseContourLoadBalancerService(sc.contourLoadBalancerService)
-	if err != nil {
-		return nil, err
-	}
-	if svc, err := sc.kubeClient.CoreV1().Services(lbNamespace).Get(lbName, metav1.GetOptions{}); err != nil {
-		log.Warn(err)
-	} else {
-		for _, lb := range svc.Status.LoadBalancer.Ingress {
-			if lb.IP != "" {
-				targets = append(targets, lb.IP)
-			}
-			if lb.Hostname != "" {
-				targets = append(targets, lb.Hostname)
-			}
-		}
-	}
-
-	return
-}
-
-// endpointsFromIngressRouteConfig extracts the endpoints from a Contour IngressRoute object
-func (sc *ingressRouteSource) endpointsFromIngressRoute(ingressRoute *contourapi.IngressRoute) ([]*endpoint.Endpoint, error) {
-	if ingressRoute.CurrentStatus != "valid" {
-		log.Warn(errors.Errorf("cannot generate endpoints for ingressroute with status %s", ingressRoute.CurrentStatus))
-		return nil, nil
-	}
-
-	var endpoints []*endpoint.Endpoint
-
-	ttl, err := getTTLFromAnnotations(ingressRoute.Annotations)
-	if err != nil {
-		log.Warn(err)
-	}
-
-	targets := getTargetsFromTargetAnnotation(ingressRoute.Annotations)
-
-	if len(targets) == 0 {
-		targets, err = sc.targetsFromContourLoadBalancer()
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	providerSpecific := getProviderSpecificAnnotations(ingressRoute.Annotations)
-
-	host := ingressRoute.Spec.VirtualHost.Fqdn
-	if host != "" {
-		endpoints = append(endpoints, endpointsForHostname(host, targets, ttl, providerSpecific)...)
-	}
-
-	// Skip endpoints if we do not want entries from annotations
-	if !sc.ignoreHostnameAnnotation {
-		hostnameList := getHostnamesFromAnnotations(ingressRoute.Annotations)
-		for _, hostname := range hostnameList {
-			endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific)...)
-		}
-	}
-
-	return endpoints, nil
-}
-
-func parseContourLoadBalancerService(service string) (namespace, name string, err error) {
-	parts := strings.Split(service, "/")
-	if len(parts) != 2 {
-		err = fmt.Errorf("invalid contour load balancer service (namespace/name) found '%v'", service)
-	} else {
-		namespace, name = parts[0], parts[1]
-	}
-
-	return
-}
diff --git a/source/store.go b/source/store.go
index d48a6398..5491085e 100644
--- a/source/store.go
+++ b/source/store.go
@@ -26,7 +26,6 @@ import (
 	"sync"
 
 	cfclient "github.com/cloudfoundry-community/go-cfclient"
-	contour "github.com/heptio/contour/apis/generated/clientset/versioned"
 	"github.com/linki/instrumented_http"
 	log "github.com/sirupsen/logrus"
 	istiocrd "istio.io/istio/pilot/pkg/config/kube/crd"
@@ -58,7 +57,6 @@ type Config struct {
 	CFAPIEndpoint               string
 	CFUsername                  string
 	CFPassword                  string
-	ContourLoadBalancerService  string
 }
 
 // ClientGenerator provides clients
@@ -66,7 +64,6 @@ type ClientGenerator interface {
 	KubeClient() (kubernetes.Interface, error)
 	IstioClient() (istiomodel.ConfigStore, error)
 	CloudFoundryClient(cfAPPEndpoint string, cfUsername string, cfPassword string) (*cfclient.Client, error)
-	ContourClient() (contour.Interface, error)
 }
 
 // SingletonClientGenerator stores provider clients and guarantees that only one instance of client
@@ -78,11 +75,9 @@ type SingletonClientGenerator struct {
 	kubeClient     kubernetes.Interface
 	istioClient    istiomodel.ConfigStore
 	cfClient       *cfclient.Client
-	contourClient  contour.Interface
 	kubeOnce       sync.Once
 	istioOnce      sync.Once
 	cfOnce         sync.Once
-	contourOnce    sync.Once
 }
 
 // KubeClient generates a kube client if it was not created before
@@ -127,15 +122,6 @@ func NewCFClient(cfAPIEndpoint string, cfUsername string, cfPassword string) (*c
 	return client, nil
 }
 
-// ContourClient generates a contour client if it was not created before
-func (p *SingletonClientGenerator) ContourClient() (contour.Interface, error) {
-	var err error
-	p.contourOnce.Do(func() {
-		p.contourClient, err = NewContourClient(p.KubeConfig, p.KubeMaster, p.RequestTimeout)
-	})
-	return p.contourClient, err
-}
-
 // ByNames returns multiple Sources given multiple names.
 func ByNames(p ClientGenerator, names []string, cfg *Config) ([]Source, error) {
 	sources := []Source{}
@@ -181,16 +167,6 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err
 			return nil, err
 		}
 		return NewCloudFoundrySource(cfClient)
-	case "contour-ingressroute":
-		kubernetesClient, err := p.KubeClient()
-		if err != nil {
-			return nil, err
-		}
-		contourClient, err := p.ContourClient()
-		if err != nil {
-			return nil, err
-		}
-		return NewContourIngressRouteSource(kubernetesClient, contourClient, cfg.ContourLoadBalancerService, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation)
 	case "fake":
 		return NewFakeSource(cfg.FQDNTemplate)
 	case "connector":
@@ -274,39 +250,3 @@ func NewIstioClient(kubeConfig string) (*istiocrd.Client, error) {
 
 	return client, nil
 }
-
-// NewContourClient returns a new Contour client object. It takes a Config and
-// uses KubeMaster and KubeConfig attributes to connect to the cluster. If
-// KubeConfig isn't provided it defaults to using the recommended default.
-func NewContourClient(kubeConfig, kubeMaster string, requestTimeout time.Duration) (*contour.Clientset, error) {
-	if kubeConfig == "" {
-		if _, err := os.Stat(clientcmd.RecommendedHomeFile); err == nil {
-			kubeConfig = clientcmd.RecommendedHomeFile
-		}
-	}
-
-	config, err := clientcmd.BuildConfigFromFlags(kubeMaster, kubeConfig)
-	if err != nil {
-		return nil, err
-	}
-
-	config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
-		return instrumented_http.NewTransport(rt, &instrumented_http.Callbacks{
-			PathProcessor: func(path string) string {
-				parts := strings.Split(path, "/")
-				return parts[len(parts)-1]
-			},
-		})
-	}
-
-	config.Timeout = requestTimeout
-
-	client, err := contour.NewForConfig(config)
-	if err != nil {
-		return nil, err
-	}
-
-	log.Infof("Created Contour client %s", config.Host)
-
-	return client, nil
-}


Test patch:
diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go
index 584e166b..f4aa011c 100644
--- a/pkg/apis/externaldns/types_test.go
+++ b/pkg/apis/externaldns/types_test.go
@@ -33,7 +33,6 @@ var (
 		KubeConfig:                  "",
 		RequestTimeout:              time.Second * 30,
 		IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway"},
-		ContourLoadBalancerService:  "heptio-contour/contour",
 		Sources:                     []string{"service"},
 		Namespace:                   "",
 		FQDNTemplate:                "",
@@ -56,7 +55,6 @@ var (
 		AzureResourceGroup:          "",
 		CloudflareProxied:           false,
 		CloudflareZonesPerPage:      50,
-		CoreDNSPrefix:               "/skydns/",
 		InfobloxGridHost:            "",
 		InfobloxWapiPort:            443,
 		InfobloxWapiUsername:        "admin",
@@ -96,7 +94,6 @@ var (
 		KubeConfig:                  "/some/path",
 		RequestTimeout:              time.Second * 77,
 		IstioIngressGatewayServices: []string{"istio-other/istio-otheringressgateway"},
-		ContourLoadBalancerService:  "heptio-contour-other/contour-other",
 		Sources:                     []string{"service", "ingress", "connector"},
 		Namespace:                   "namespace",
 		IgnoreHostnameAnnotation:    true,
@@ -120,7 +117,6 @@ var (
 		AzureResourceGroup:          "arg",
 		CloudflareProxied:           true,
 		CloudflareZonesPerPage:      20,
-		CoreDNSPrefix:               "/coredns/",
 		InfobloxGridHost:            "127.0.0.1",
 		InfobloxWapiPort:            8443,
 		InfobloxWapiUsername:        "infoblox",
@@ -168,7 +164,6 @@ var (
 		RequestTimeout:              time.Second * 30,
 		IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway", "istio-other/istio-otheringressgateway"},
 		Sources:                     []string{"istio-gateway"},
-		ContourLoadBalancerService:  "heptio-contour/contour",
 		Namespace:                   "",
 		FQDNTemplate:                "",
 		Compatibility:               "",
@@ -190,7 +185,6 @@ var (
 		AzureResourceGroup:          "",
 		CloudflareProxied:           false,
 		CloudflareZonesPerPage:      50,
-		CoreDNSPrefix:               "/skydns/",
 		InfobloxGridHost:            "",
 		InfobloxWapiPort:            443,
 		InfobloxWapiUsername:        "admin",
@@ -246,7 +240,6 @@ func TestParseFlags(t *testing.T) {
 				"--kubeconfig=/some/path",
 				"--request-timeout=77s",
 				"--istio-ingress-gateway=istio-other/istio-otheringressgateway",
-				"--contour-load-balancer=heptio-contour-other/contour-other",
 				"--source=service",
 				"--source=ingress",
 				"--source=connector",
@@ -260,7 +253,6 @@ func TestParseFlags(t *testing.T) {
 				"--azure-resource-group=arg",
 				"--cloudflare-proxied",
 				"--cloudflare-zones-per-page=20",
-				"--coredns-prefix=/coredns/",
 				"--infoblox-grid-host=127.0.0.1",
 				"--infoblox-wapi-port=8443",
 				"--infoblox-wapi-username=infoblox",
@@ -326,7 +318,6 @@ func TestParseFlags(t *testing.T) {
 				"EXTERNAL_DNS_KUBECONFIG":                 "/some/path",
 				"EXTERNAL_DNS_REQUEST_TIMEOUT":            "77s",
 				"EXTERNAL_DNS_ISTIO_INGRESS_GATEWAY":      "istio-other/istio-otheringressgateway",
-				"EXTERNAL_DNS_CONTOUR_LOAD_BALANCER":      "heptio-contour-other/contour-other",
 				"EXTERNAL_DNS_SOURCE":                     "service\ningress\nconnector",
 				"EXTERNAL_DNS_NAMESPACE":                  "namespace",
 				"EXTERNAL_DNS_FQDN_TEMPLATE":              "{{.Name}}.service.example.com",
@@ -338,7 +329,6 @@ func TestParseFlags(t *testing.T) {
 				"EXTERNAL_DNS_AZURE_RESOURCE_GROUP":       "arg",
 				"EXTERNAL_DNS_CLOUDFLARE_PROXIED":         "1",
 				"EXTERNAL_DNS_CLOUDFLARE_ZONES_PER_PAGE":  "20",
-				"EXTERNAL_DNS_COREDNS_PREFIX":             "/coredns/",
 				"EXTERNAL_DNS_INFOBLOX_GRID_HOST":         "127.0.0.1",
 				"EXTERNAL_DNS_INFOBLOX_WAPI_PORT":         "8443",
 				"EXTERNAL_DNS_INFOBLOX_WAPI_USERNAME":     "infoblox",
diff --git a/provider/coredns_test.go b/provider/coredns_test.go
index e86cc2fe..698207a0 100644
--- a/provider/coredns_test.go
+++ b/provider/coredns_test.go
@@ -25,8 +25,6 @@ import (
 	"github.com/kubernetes-incubator/external-dns/plan"
 )
 
-const defaultCoreDNSPrefix = "/skydns/"
-
 type fakeETCDClient struct {
 	services map[string]*Service
 }
@@ -62,10 +60,7 @@ func TestAServiceTranslation(t *testing.T) {
 			"/skydns/com/example": {Host: expectedTarget},
 		},
 	}
-	provider := coreDNSProvider{
-		client:        client,
-		coreDNSPrefix: defaultCoreDNSPrefix,
-	}
+	provider := coreDNSProvider{client: client}
 	endpoints, err := provider.Records()
 	if err != nil {
 		t.Fatal(err)
@@ -94,10 +89,7 @@ func TestCNAMEServiceTranslation(t *testing.T) {
 			"/skydns/com/example": {Host: expectedTarget},
 		},
 	}
-	provider := coreDNSProvider{
-		client:        client,
-		coreDNSPrefix: defaultCoreDNSPrefix,
-	}
+	provider := coreDNSProvider{client: client}
 	endpoints, err := provider.Records()
 	if err != nil {
 		t.Fatal(err)
@@ -126,10 +118,7 @@ func TestTXTServiceTranslation(t *testing.T) {
 			"/skydns/com/example": {Text: expectedTarget},
 		},
 	}
-	provider := coreDNSProvider{
-		client:        client,
-		coreDNSPrefix: defaultCoreDNSPrefix,
-	}
+	provider := coreDNSProvider{client: client}
 	endpoints, err := provider.Records()
 	if err != nil {
 		t.Fatal(err)
@@ -160,10 +149,7 @@ func TestAWithTXTServiceTranslation(t *testing.T) {
 			"/skydns/com/example": {Host: "1.2.3.4", Text: "string"},
 		},
 	}
-	provider := coreDNSProvider{
-		client:        client,
-		coreDNSPrefix: defaultCoreDNSPrefix,
-	}
+	provider := coreDNSProvider{client: client}
 	endpoints, err := provider.Records()
 	if err != nil {
 		t.Fatal(err)
@@ -202,10 +188,7 @@ func TestCNAMEWithTXTServiceTranslation(t *testing.T) {
 			"/skydns/com/example": {Host: "example.net", Text: "string"},
 		},
 	}
-	provider := coreDNSProvider{
-		client:        client,
-		coreDNSPrefix: defaultCoreDNSPrefix,
-	}
+	provider := coreDNSProvider{client: client}
 	endpoints, err := provider.Records()
 	if err != nil {
 		t.Fatal(err)
@@ -236,10 +219,7 @@ func TestCoreDNSApplyChanges(t *testing.T) {
 	client := fakeETCDClient{
 		map[string]*Service{},
 	}
-	coredns := coreDNSProvider{
-		client:        client,
-		coreDNSPrefix: defaultCoreDNSPrefix,
-	}
+	coredns := coreDNSProvider{client: client}
 
 	changes1 := &plan.Changes{
 		Create: []*endpoint.Endpoint{
diff --git a/source/ingressroute_test.go b/source/ingressroute_test.go
deleted file mode 100644
index 8edcc1d9..00000000
--- a/source/ingressroute_test.go
+++ /dev/null
@@ -1,1094 +0,0 @@
-/*
-Copyright 2017 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 (
-	"testing"
-
-	contour "github.com/heptio/contour/apis/contour/v1beta1"
-	fakeContour "github.com/heptio/contour/apis/generated/clientset/versioned/fake"
-	"github.com/pkg/errors"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"github.com/stretchr/testify/suite"
-	v1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	fakeKube "k8s.io/client-go/kubernetes/fake"
-
-	"github.com/kubernetes-incubator/external-dns/endpoint"
-)
-
-// This is a compile-time validation that ingressRouteSource is a Source.
-var _ Source = &ingressRouteSource{}
-
-type IngressRouteSuite struct {
-	suite.Suite
-	source       Source
-	loadBalancer *v1.Service
-	ingressRoute *contour.IngressRoute
-}
-
-func (suite *IngressRouteSuite) SetupTest() {
-	fakeKubernetesClient := fakeKube.NewSimpleClientset()
-	fakeContourClient := fakeContour.NewSimpleClientset()
-	var err error
-
-	suite.loadBalancer = (fakeLoadBalancerService{
-		ips:       []string{"8.8.8.8"},
-		hostnames: []string{"v1"},
-		namespace: "heptio-contour/contour",
-		name:      "contour",
-	}).Service()
-
-	_, err = fakeKubernetesClient.CoreV1().Services(suite.loadBalancer.Namespace).Create(suite.loadBalancer)
-	suite.NoError(err, "should succeed")
-
-	suite.source, err = NewContourIngressRouteSource(
-		fakeKubernetesClient,
-		fakeContourClient,
-		"heptio-contour/contour",
-		"default",
-		"",
-		"{{.Name}}",
-		false,
-		false,
-	)
-	suite.NoError(err, "should initialize ingressroute source")
-
-	suite.ingressRoute = (fakeIngressRoute{
-		name:      "foo-ingressroute-with-targets",
-		namespace: "default",
-		host:      "example.com",
-	}).IngressRoute()
-	_, err = fakeContourClient.ContourV1beta1().IngressRoutes(suite.ingressRoute.Namespace).Create(suite.ingressRoute)
-	suite.NoError(err, "should succeed")
-}
-
-func (suite *IngressRouteSuite) TestResourceLabelIsSet() {
-	endpoints, _ := suite.source.Endpoints()
-	for _, ep := range endpoints {
-		suite.Equal("ingressroute/default/foo-ingressroute-with-targets", ep.Labels[endpoint.ResourceLabelKey], "should set correct resource label")
-	}
-}
-
-func TestIngressRoute(t *testing.T) {
-	suite.Run(t, new(IngressRouteSuite))
-	t.Run("endpointsFromIngressRoute", testEndpointsFromIngressRoute)
-	t.Run("Endpoints", testIngressRouteEndpoints)
-}
-
-func TestNewContourIngressRouteSource(t *testing.T) {
-	for _, ti := range []struct {
-		title                    string
-		annotationFilter         string
-		fqdnTemplate             string
-		combineFQDNAndAnnotation bool
-		expectError              bool
-	}{
-		{
-			title:        "invalid template",
-			expectError:  true,
-			fqdnTemplate: "{{.Name",
-		},
-		{
-			title:       "valid empty template",
-			expectError: false,
-		},
-		{
-			title:        "valid template",
-			expectError:  false,
-			fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com",
-		},
-		{
-			title:        "valid template",
-			expectError:  false,
-			fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com",
-		},
-		{
-			title:                    "valid template",
-			expectError:              false,
-			fqdnTemplate:             "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com",
-			combineFQDNAndAnnotation: true,
-		},
-		{
-			title:            "non-empty annotation filter label",
-			expectError:      false,
-			annotationFilter: "contour.heptio.com/ingress.class=contour",
-		},
-	} {
-		t.Run(ti.title, func(t *testing.T) {
-			_, err := NewContourIngressRouteSource(
-				fakeKube.NewSimpleClientset(),
-				fakeContour.NewSimpleClientset(),
-				"heptio-contour/contour",
-				"",
-				ti.annotationFilter,
-				ti.fqdnTemplate,
-				ti.combineFQDNAndAnnotation,
-				false,
-			)
-			if ti.expectError {
-				assert.Error(t, err)
-			} else {
-				assert.NoError(t, err)
-			}
-		})
-	}
-}
-
-func testEndpointsFromIngressRoute(t *testing.T) {
-	for _, ti := range []struct {
-		title        string
-		loadBalancer fakeLoadBalancerService
-		ingressRoute fakeIngressRoute
-		expected     []*endpoint.Endpoint
-	}{
-		{
-			title: "one rule.host one lb.hostname",
-			loadBalancer: fakeLoadBalancerService{
-				hostnames: []string{"lb.com"}, // Kubernetes omits the trailing dot
-			},
-			ingressRoute: fakeIngressRoute{
-				host: "foo.bar", // Kubernetes requires removal of trailing dot
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "foo.bar",
-					Targets: endpoint.Targets{"lb.com"},
-				},
-			},
-		},
-		{
-			title: "one rule.host one lb.IP",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRoute: fakeIngressRoute{
-				host: "foo.bar",
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "foo.bar",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-			},
-		},
-		{
-			title: "one rule.host two lb.IP and two lb.Hostname",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{"8.8.8.8", "127.0.0.1"},
-				hostnames: []string{"elb.com", "alb.com"},
-			},
-			ingressRoute: fakeIngressRoute{
-				host: "foo.bar",
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "foo.bar",
-					Targets: endpoint.Targets{"8.8.8.8", "127.0.0.1"},
-				},
-				{
-					DNSName: "foo.bar",
-					Targets: endpoint.Targets{"elb.com", "alb.com"},
-				},
-			},
-		},
-		{
-			title: "no rule.host",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{"8.8.8.8", "127.0.0.1"},
-				hostnames: []string{"elb.com", "alb.com"},
-			},
-			ingressRoute: fakeIngressRoute{},
-			expected:     []*endpoint.Endpoint{},
-		},
-		{
-			title: "one rule.host invalid ingressroute",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{"8.8.8.8", "127.0.0.1"},
-				hostnames: []string{"elb.com", "alb.com"},
-			},
-			ingressRoute: fakeIngressRoute{
-				host:    "foo.bar",
-				invalid: true,
-			},
-			expected: []*endpoint.Endpoint{},
-		},
-		{
-			title:        "no targets",
-			loadBalancer: fakeLoadBalancerService{},
-			ingressRoute: fakeIngressRoute{},
-			expected:     []*endpoint.Endpoint{},
-		},
-	} {
-		t.Run(ti.title, func(t *testing.T) {
-			if source, err := newTestIngressRouteSource(ti.loadBalancer); err != nil {
-				require.NoError(t, err)
-			} else if endpoints, err := source.endpointsFromIngressRoute(ti.ingressRoute.IngressRoute()); err != nil {
-				require.NoError(t, err)
-			} else {
-				validateEndpoints(t, endpoints, ti.expected)
-			}
-		})
-	}
-}
-
-func testIngressRouteEndpoints(t *testing.T) {
-	namespace := "testing"
-	for _, ti := range []struct {
-		title                    string
-		targetNamespace          string
-		annotationFilter         string
-		loadBalancer             fakeLoadBalancerService
-		ingressRouteItems        []fakeIngressRoute
-		expected                 []*endpoint.Endpoint
-		expectError              bool
-		fqdnTemplate             string
-		combineFQDNAndAnnotation bool
-		ignoreHostnameAnnotation bool
-	}{
-		{
-			title:           "no ingressroute",
-			targetNamespace: "",
-		},
-		{
-			title:           "two simple ingressroutes",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{"8.8.8.8"},
-				hostnames: []string{"lb.com"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					host:      "example.org",
-				},
-				{
-					name:      "fake2",
-					namespace: namespace,
-					host:      "new.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"lb.com"},
-				},
-				{
-					DNSName: "new.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-				{
-					DNSName: "new.org",
-					Targets: endpoint.Targets{"lb.com"},
-				},
-			},
-		},
-		{
-			title:           "two simple ingressroutes on different namespaces",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{"8.8.8.8"},
-				hostnames: []string{"lb.com"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: "testing1",
-					host:      "example.org",
-				},
-				{
-					name:      "fake2",
-					namespace: "testing2",
-					host:      "new.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"lb.com"},
-				},
-				{
-					DNSName: "new.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-				{
-					DNSName: "new.org",
-					Targets: endpoint.Targets{"lb.com"},
-				},
-			},
-		},
-		{
-			title:           "two simple ingressroutes on different namespaces and a target namespace",
-			targetNamespace: "testing1",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{"8.8.8.8"},
-				hostnames: []string{"lb.com"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: "testing1",
-					host:      "example.org",
-				},
-				{
-					name:      "fake2",
-					namespace: "testing2",
-					host:      "new.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"lb.com"},
-				},
-			},
-		},
-		{
-			title:            "valid matching annotation filter expression",
-			targetNamespace:  "",
-			annotationFilter: "contour.heptio.com/ingress.class in (alb, contour)",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						"contour.heptio.com/ingress.class": "contour",
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-			},
-		},
-		{
-			title:            "valid non-matching annotation filter expression",
-			targetNamespace:  "",
-			annotationFilter: "contour.heptio.com/ingress.class in (alb, contour)",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						"contour.heptio.com/ingress.class": "tectonic",
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{},
-		},
-		{
-			title:            "invalid annotation filter expression",
-			targetNamespace:  "",
-			annotationFilter: "contour.heptio.com/ingress.name in (a b)",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						"contour.heptio.com/ingress.class": "alb",
-					},
-					host: "example.org",
-				},
-			},
-			expected:    []*endpoint.Endpoint{},
-			expectError: true,
-		},
-		{
-			title:            "valid matching annotation filter label",
-			targetNamespace:  "",
-			annotationFilter: "contour.heptio.com/ingress.class=contour",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						"contour.heptio.com/ingress.class": "contour",
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-			},
-		},
-		{
-			title:            "valid non-matching annotation filter label",
-			targetNamespace:  "",
-			annotationFilter: "contour.heptio.com/ingress.class=contour",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						"contour.heptio.com/ingress.class": "alb",
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{},
-		},
-		{
-			title:           "our controller type is dns-controller",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						controllerAnnotationKey: controllerAnnotationValue,
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-			},
-		},
-		{
-			title:           "different controller types are ignored",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						controllerAnnotationKey: "some-other-tool",
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{},
-		},
-		{
-			title:           "template for ingressroute if host is missing",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{"8.8.8.8"},
-				hostnames: []string{"elb.com"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						controllerAnnotationKey: controllerAnnotationValue,
-					},
-					host: "",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "fake1.ext-dns.test.com",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-				{
-					DNSName: "fake1.ext-dns.test.com",
-					Targets: endpoint.Targets{"elb.com"},
-				},
-			},
-			fqdnTemplate: "{{.Name}}.ext-dns.test.com",
-		},
-		{
-			title:           "another controller annotation skipped even with template",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						controllerAnnotationKey: "other-controller",
-					},
-					host: "",
-				},
-			},
-			expected:     []*endpoint.Endpoint{},
-			fqdnTemplate: "{{.Name}}.ext-dns.test.com",
-		},
-		{
-			title:           "multiple FQDN template hostnames",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:        "fake1",
-					namespace:   namespace,
-					annotations: map[string]string{},
-					host:        "",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName:    "fake1.ext-dns.test.com",
-					Targets:    endpoint.Targets{"8.8.8.8"},
-					RecordType: endpoint.RecordTypeA,
-				},
-				{
-					DNSName:    "fake1.ext-dna.test.com",
-					Targets:    endpoint.Targets{"8.8.8.8"},
-					RecordType: endpoint.RecordTypeA,
-				},
-			},
-			fqdnTemplate: "{{.Name}}.ext-dns.test.com, {{.Name}}.ext-dna.test.com",
-		},
-		{
-			title:           "multiple FQDN template hostnames",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:        "fake1",
-					namespace:   namespace,
-					annotations: map[string]string{},
-					host:        "",
-				},
-				{
-					name:      "fake2",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "ingressroute-target.com",
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName:    "fake1.ext-dns.test.com",
-					Targets:    endpoint.Targets{"8.8.8.8"},
-					RecordType: endpoint.RecordTypeA,
-				},
-				{
-					DNSName:    "fake1.ext-dna.test.com",
-					Targets:    endpoint.Targets{"8.8.8.8"},
-					RecordType: endpoint.RecordTypeA,
-				},
-				{
-					DNSName:    "example.org",
-					Targets:    endpoint.Targets{"ingressroute-target.com"},
-					RecordType: endpoint.RecordTypeCNAME,
-				},
-				{
-					DNSName:    "fake2.ext-dns.test.com",
-					Targets:    endpoint.Targets{"ingressroute-target.com"},
-					RecordType: endpoint.RecordTypeCNAME,
-				},
-				{
-					DNSName:    "fake2.ext-dna.test.com",
-					Targets:    endpoint.Targets{"ingressroute-target.com"},
-					RecordType: endpoint.RecordTypeCNAME,
-				},
-			},
-			fqdnTemplate:             "{{.Name}}.ext-dns.test.com, {{.Name}}.ext-dna.test.com",
-			combineFQDNAndAnnotation: true,
-		},
-		{
-			title:           "ingressroute rules with annotation",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "ingressroute-target.com",
-					},
-					host: "example.org",
-				},
-				{
-					name:      "fake2",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "ingressroute-target.com",
-					},
-					host: "example2.org",
-				},
-				{
-					name:      "fake3",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "1.2.3.4",
-					},
-					host: "example3.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName:    "example.org",
-					Targets:    endpoint.Targets{"ingressroute-target.com"},
-					RecordType: endpoint.RecordTypeCNAME,
-				},
-				{
-					DNSName:    "example2.org",
-					Targets:    endpoint.Targets{"ingressroute-target.com"},
-					RecordType: endpoint.RecordTypeCNAME,
-				},
-				{
-					DNSName:    "example3.org",
-					Targets:    endpoint.Targets{"1.2.3.4"},
-					RecordType: endpoint.RecordTypeA,
-				},
-			},
-		},
-		{
-			title:           "ingressroute rules with hostname annotation",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"1.2.3.4"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						hostnameAnnotationKey: "dns-through-hostname.com",
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName:    "example.org",
-					Targets:    endpoint.Targets{"1.2.3.4"},
-					RecordType: endpoint.RecordTypeA,
-				},
-				{
-					DNSName:    "dns-through-hostname.com",
-					Targets:    endpoint.Targets{"1.2.3.4"},
-					RecordType: endpoint.RecordTypeA,
-				},
-			},
-		},
-		{
-			title:           "ingressroute rules with hostname annotation having multiple hostnames",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"1.2.3.4"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						hostnameAnnotationKey: "dns-through-hostname.com, another-dns-through-hostname.com",
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName:    "example.org",
-					Targets:    endpoint.Targets{"1.2.3.4"},
-					RecordType: endpoint.RecordTypeA,
-				},
-				{
-					DNSName:    "dns-through-hostname.com",
-					Targets:    endpoint.Targets{"1.2.3.4"},
-					RecordType: endpoint.RecordTypeA,
-				},
-				{
-					DNSName:    "another-dns-through-hostname.com",
-					Targets:    endpoint.Targets{"1.2.3.4"},
-					RecordType: endpoint.RecordTypeA,
-				},
-			},
-		},
-		{
-			title:           "ingressroute rules with hostname and target annotation",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						hostnameAnnotationKey: "dns-through-hostname.com",
-						targetAnnotationKey:   "ingressroute-target.com",
-					},
-					host: "example.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName:    "example.org",
-					Targets:    endpoint.Targets{"ingressroute-target.com"},
-					RecordType: endpoint.RecordTypeCNAME,
-				},
-				{
-					DNSName:    "dns-through-hostname.com",
-					Targets:    endpoint.Targets{"ingressroute-target.com"},
-					RecordType: endpoint.RecordTypeCNAME,
-				},
-			},
-		},
-		{
-			title:           "ingressroute rules with annotation and custom TTL",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips: []string{"8.8.8.8"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "ingressroute-target.com",
-						ttlAnnotationKey:    "6",
-					},
-					host: "example.org",
-				},
-				{
-					name:      "fake2",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "ingressroute-target.com",
-						ttlAnnotationKey:    "1",
-					},
-					host: "example2.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName:   "example.org",
-					Targets:   endpoint.Targets{"ingressroute-target.com"},
-					RecordTTL: endpoint.TTL(6),
-				},
-				{
-					DNSName:   "example2.org",
-					Targets:   endpoint.Targets{"ingressroute-target.com"},
-					RecordTTL: endpoint.TTL(1),
-				},
-			},
-		},
-		{
-			title:           "template for ingressroute with annotation",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{},
-				hostnames: []string{},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "ingressroute-target.com",
-					},
-					host: "",
-				},
-				{
-					name:      "fake2",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "ingressroute-target.com",
-					},
-					host: "",
-				},
-				{
-					name:      "fake3",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "1.2.3.4",
-					},
-					host: "",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName:    "fake1.ext-dns.test.com",
-					Targets:    endpoint.Targets{"ingressroute-target.com"},
-					RecordType: endpoint.RecordTypeCNAME,
-				},
-				{
-					DNSName:    "fake2.ext-dns.test.com",
-					Targets:    endpoint.Targets{"ingressroute-target.com"},
-					RecordType: endpoint.RecordTypeCNAME,
-				},
-				{
-					DNSName:    "fake3.ext-dns.test.com",
-					Targets:    endpoint.Targets{"1.2.3.4"},
-					RecordType: endpoint.RecordTypeA,
-				},
-			},
-			fqdnTemplate: "{{.Name}}.ext-dns.test.com",
-		},
-		{
-			title:           "ingressroute with empty annotation",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{},
-				hostnames: []string{},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						targetAnnotationKey: "",
-					},
-					host: "",
-				},
-			},
-			expected:     []*endpoint.Endpoint{},
-			fqdnTemplate: "{{.Name}}.ext-dns.test.com",
-		},
-		{
-			title:           "ignore hostname annotations",
-			targetNamespace: "",
-			loadBalancer: fakeLoadBalancerService{
-				ips:       []string{"8.8.8.8"},
-				hostnames: []string{"lb.com"},
-			},
-			ingressRouteItems: []fakeIngressRoute{
-				{
-					name:      "fake1",
-					namespace: namespace,
-					annotations: map[string]string{
-						hostnameAnnotationKey: "ignore.me",
-					},
-					host: "example.org",
-				},
-				{
-					name:      "fake2",
-					namespace: namespace,
-					annotations: map[string]string{
-						hostnameAnnotationKey: "ignore.me.too",
-					},
-					host: "new.org",
-				},
-			},
-			expected: []*endpoint.Endpoint{
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-				{
-					DNSName: "example.org",
-					Targets: endpoint.Targets{"lb.com"},
-				},
-				{
-					DNSName: "new.org",
-					Targets: endpoint.Targets{"8.8.8.8"},
-				},
-				{
-					DNSName: "new.org",
-					Targets: endpoint.Targets{"lb.com"},
-				},
-			},
-			ignoreHostnameAnnotation: true,
-		},
-	} {
-		t.Run(ti.title, func(t *testing.T) {
-			ingressRoutes := make([]*contour.IngressRoute, 0)
-			for _, item := range ti.ingressRouteItems {
-				ingressRoutes = append(ingressRoutes, item.IngressRoute())
-			}
-
-			fakeKubernetesClient := fakeKube.NewSimpleClientset()
-
-			lbService := ti.loadBalancer.Service()
-			_, err := fakeKubernetesClient.CoreV1().Services(lbService.Namespace).Create(lbService)
-			if err != nil {
-				require.NoError(t, err)
-			}
-
-			fakeContourClient := fakeContour.NewSimpleClientset()
-			for _, ingressRoute := range ingressRoutes {
-				_, err := fakeContourClient.ContourV1beta1().IngressRoutes(ingressRoute.Namespace).Create(ingressRoute)
-				require.NoError(t, err)
-			}
-
-			ingressRouteSource, err := NewContourIngressRouteSource(
-				fakeKubernetesClient,
-				fakeContourClient,
-				lbService.Namespace+"/"+lbService.Name,
-				ti.targetNamespace,
-				ti.annotationFilter,
-				ti.fqdnTemplate,
-				ti.combineFQDNAndAnnotation,
-				ti.ignoreHostnameAnnotation,
-			)
-			require.NoError(t, err)
-
-			res, err := ingressRouteSource.Endpoints()
-			if ti.expectError {
-				assert.Error(t, err)
-			} else {
-				assert.NoError(t, err)
-			}
-
-			validateEndpoints(t, res, ti.expected)
-		})
-	}
-}
-
-// ingressroute specific helper functions
-func newTestIngressRouteSource(loadBalancer fakeLoadBalancerService) (*ingressRouteSource, error) {
-	fakeKubernetesClient := fakeKube.NewSimpleClientset()
-	fakeContourClient := fakeContour.NewSimpleClientset()
-
-	lbService := loadBalancer.Service()
-	_, err := fakeKubernetesClient.CoreV1().Services(lbService.Namespace).Create(lbService)
-	if err != nil {
-		return nil, err
-	}
-
-	src, err := NewContourIngressRouteSource(
-		fakeKubernetesClient,
-		fakeContourClient,
-		lbService.Namespace+"/"+lbService.Name,
-		"default",
-		"",
-		"{{.Name}}",
-		false,
-		false,
-	)
-	if err != nil {
-		return nil, err
-	}
-
-	irsrc, ok := src.(*ingressRouteSource)
-	if !ok {
-		return nil, errors.New("underlying source type was not ingressroute")
-	}
-
-	return irsrc, nil
-}
-
-type fakeLoadBalancerService struct {
-	ips       []string
-	hostnames []string
-	namespace string
-	name      string
-}
-
-func (ig fakeLoadBalancerService) Service() *v1.Service {
-	svc := &v1.Service{
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace: ig.namespace,
-			Name:      ig.name,
-		},
-		Status: v1.ServiceStatus{
-			LoadBalancer: v1.LoadBalancerStatus{
-				Ingress: []v1.LoadBalancerIngress{},
-			},
-		},
-	}
-
-	for _, ip := range ig.ips {
-		svc.Status.LoadBalancer.Ingress = append(svc.Status.LoadBalancer.Ingress, v1.LoadBalancerIngress{
-			IP: ip,
-		})
-	}
-	for _, hostname := range ig.hostnames {
-		svc.Status.LoadBalancer.Ingress = append(svc.Status.LoadBalancer.Ingress, v1.LoadBalancerIngress{
-			Hostname: hostname,
-		})
-	}
-
-	return svc
-}
-
-type fakeIngressRoute struct {
-	namespace   string
-	name        string
-	annotations map[string]string
-
-	host    string
-	invalid bool
-}
-
-func (ir fakeIngressRoute) IngressRoute() *contour.IngressRoute {
-	var status string
-	if ir.invalid {
-		status = "invalid"
-	} else {
-		status = "valid"
-	}
-
-	ingressRoute := &contour.IngressRoute{
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace:   ir.namespace,
-			Name:        ir.name,
-			Annotations: ir.annotations,
-		},
-		Spec: contour.IngressRouteSpec{
-			VirtualHost: &contour.VirtualHost{
-				Fqdn: ir.host,
-			},
-		},
-		Status: contour.Status{
-			CurrentStatus: status,
-		},
-	}
-
-	return ingressRoute
-}
diff --git a/source/store_test.go b/source/store_test.go
index 5377fce4..176ac9bb 100644
--- a/source/store_test.go
+++ b/source/store_test.go
@@ -20,14 +20,13 @@ import (
 	"errors"
 	"testing"
 
-	cfclient "github.com/cloudfoundry-community/go-cfclient"
-	contour "github.com/heptio/contour/apis/generated/clientset/versioned"
-	fakeContour "github.com/heptio/contour/apis/generated/clientset/versioned/fake"
-	"github.com/stretchr/testify/mock"
-	"github.com/stretchr/testify/suite"
 	istiomodel "istio.io/istio/pilot/pkg/model"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes/fake"
+
+	cfclient "github.com/cloudfoundry-community/go-cfclient"
+	"github.com/stretchr/testify/mock"
+	"github.com/stretchr/testify/suite"
 )
 
 type MockClientGenerator struct {
@@ -35,7 +34,6 @@ type MockClientGenerator struct {
 	kubeClient         kubernetes.Interface
 	istioClient        istiomodel.ConfigStore
 	cloudFoundryClient *cfclient.Client
-	contourClient      contour.Interface
 }
 
 func (m *MockClientGenerator) KubeClient() (kubernetes.Interface, error) {
@@ -65,15 +63,6 @@ func (m *MockClientGenerator) CloudFoundryClient(cfAPIEndpoint string, cfUsernam
 	return nil, args.Error(1)
 }
 
-func (m *MockClientGenerator) ContourClient() (contour.Interface, error) {
-	args := m.Called()
-	if args.Error(1) == nil {
-		m.contourClient = args.Get(0).(contour.Interface)
-		return m.contourClient, nil
-	}
-	return nil, args.Error(1)
-}
-
 type ByNamesTestSuite struct {
 	suite.Suite
 }
@@ -82,11 +71,10 @@ func (suite *ByNamesTestSuite) TestAllInitialized() {
 	mockClientGenerator := new(MockClientGenerator)
 	mockClientGenerator.On("KubeClient").Return(fake.NewSimpleClientset(), nil)
 	mockClientGenerator.On("IstioClient").Return(NewFakeConfigStore(), nil)
-	mockClientGenerator.On("ContourClient").Return(fakeContour.NewSimpleClientset(), nil)
 
-	sources, err := ByNames(mockClientGenerator, []string{"service", "ingress", "istio-gateway", "contour-ingressroute", "fake"}, minimalConfig)
+	sources, err := ByNames(mockClientGenerator, []string{"service", "ingress", "istio-gateway", "fake"}, minimalConfig)
 	suite.NoError(err, "should not generate errors")
-	suite.Len(sources, 5, "should generate all five sources")
+	suite.Len(sources, 4, "should generate all four sources")
 }
 
 func (suite *ByNamesTestSuite) TestOnlyFake() {
@@ -120,22 +108,15 @@ func (suite *ByNamesTestSuite) TestKubeClientFails() {
 
 	_, err = ByNames(mockClientGenerator, []string{"istio-gateway"}, minimalConfig)
 	suite.Error(err, "should return an error if kubernetes client cannot be created")
-
-	_, err = ByNames(mockClientGenerator, []string{"contour-ingressroute"}, minimalConfig)
-	suite.Error(err, "should return an error if kubernetes client cannot be created")
 }
 
 func (suite *ByNamesTestSuite) TestIstioClientFails() {
 	mockClientGenerator := new(MockClientGenerator)
 	mockClientGenerator.On("KubeClient").Return(fake.NewSimpleClientset(), nil)
 	mockClientGenerator.On("IstioClient").Return(nil, errors.New("foo"))
-	mockClientGenerator.On("ContourClient").Return(nil, errors.New("foo"))
 
 	_, err := ByNames(mockClientGenerator, []string{"istio-gateway"}, minimalConfig)
 	suite.Error(err, "should return an error if istio client cannot be created")
-
-	_, err = ByNames(mockClientGenerator, []string{"contour-ingressroute"}, minimalConfig)
-	suite.Error(err, "should return an error if contour client cannot be created")
 }
 
 func TestByNames(t *testing.T) {
@@ -144,5 +125,4 @@ func TestByNames(t *testing.T) {
 
 var minimalConfig = &Config{
 	IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway"},
-	ContourLoadBalancerService:  "heptio-contour/contour",
 }