Add support for multiple Istio Ingress Gateways

The --istio-ingress-gateway flag may now be specified multiple times.
This commit is contained in:
Christian Glombek 2019-03-18 22:13:44 +01:00
parent c3702c9130
commit 0076e4156c
8 changed files with 615 additions and 425 deletions

View File

@ -25,7 +25,7 @@ spec:
- --source=service - --source=service
- --source=ingress - --source=ingress
- --source=istio-gateway - --source=istio-gateway
- --istio-ingress-gateway=custom-istio-namespace/custom-istio-ingressgateway # omit to use the default (istio-system/istio-ingressgateway) - --istio-ingress-gateway=custom-istio-namespace/custom-istio-ingressgateway # load balancer service to be used; can be specified multiple times. Omit to use the default (istio-system/istio-ingressgateway)
- --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 - --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 - --provider=aws
- --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
@ -95,7 +95,7 @@ spec:
- --source=service - --source=service
- --source=ingress - --source=ingress
- --source=istio-gateway - --source=istio-gateway
- --istio-ingress-gateway=custom-istio-namespace/custom-istio-ingressgateway # omit to use the default (istio-system/istio-ingressgateway) - --istio-ingress-gateway=custom-istio-namespace/custom-istio-ingressgateway # load balancer service to be used; can be specified multiple times. Omit to use the default (istio-system/istio-ingressgateway)
- --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 - --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 - --provider=aws
- --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization

30
main.go
View File

@ -67,21 +67,21 @@ func main() {
// Create a source.Config from the flags passed by the user. // Create a source.Config from the flags passed by the user.
sourceCfg := &source.Config{ sourceCfg := &source.Config{
Namespace: cfg.Namespace, Namespace: cfg.Namespace,
AnnotationFilter: cfg.AnnotationFilter, AnnotationFilter: cfg.AnnotationFilter,
FQDNTemplate: cfg.FQDNTemplate, FQDNTemplate: cfg.FQDNTemplate,
CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation, CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation,
IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation, IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation,
Compatibility: cfg.Compatibility, Compatibility: cfg.Compatibility,
PublishInternal: cfg.PublishInternal, PublishInternal: cfg.PublishInternal,
PublishHostIP: cfg.PublishHostIP, PublishHostIP: cfg.PublishHostIP,
ConnectorServer: cfg.ConnectorSourceServer, ConnectorServer: cfg.ConnectorSourceServer,
CRDSourceAPIVersion: cfg.CRDSourceAPIVersion, CRDSourceAPIVersion: cfg.CRDSourceAPIVersion,
CRDSourceKind: cfg.CRDSourceKind, CRDSourceKind: cfg.CRDSourceKind,
KubeConfig: cfg.KubeConfig, KubeConfig: cfg.KubeConfig,
KubeMaster: cfg.Master, KubeMaster: cfg.Master,
ServiceTypeFilter: cfg.ServiceTypeFilter, ServiceTypeFilter: cfg.ServiceTypeFilter,
IstioIngressGateway: cfg.IstioIngressGateway, IstioIngressGatewayServices: cfg.IstioIngressGatewayServices,
} }
// Lookup all the selected sources by names and pass them the desired configuration. // Lookup all the selected sources by names and pass them the desired configuration.

View File

@ -36,155 +36,155 @@ var (
// Config is a project-wide configuration // Config is a project-wide configuration
type Config struct { type Config struct {
Master string Master string
KubeConfig string KubeConfig string
RequestTimeout time.Duration RequestTimeout time.Duration
IstioIngressGateway string IstioIngressGatewayServices []string
Sources []string Sources []string
Namespace string Namespace string
AnnotationFilter string AnnotationFilter string
FQDNTemplate string FQDNTemplate string
CombineFQDNAndAnnotation bool CombineFQDNAndAnnotation bool
IgnoreHostnameAnnotation bool IgnoreHostnameAnnotation bool
Compatibility string Compatibility string
PublishInternal bool PublishInternal bool
PublishHostIP bool PublishHostIP bool
ConnectorSourceServer string ConnectorSourceServer string
Provider string Provider string
GoogleProject string GoogleProject string
DomainFilter []string DomainFilter []string
ZoneIDFilter []string ZoneIDFilter []string
AlibabaCloudConfigFile string AlibabaCloudConfigFile string
AlibabaCloudZoneType string AlibabaCloudZoneType string
AWSZoneType string AWSZoneType string
AWSZoneTagFilter []string AWSZoneTagFilter []string
AWSAssumeRole string AWSAssumeRole string
AWSBatchChangeSize int AWSBatchChangeSize int
AWSBatchChangeInterval time.Duration AWSBatchChangeInterval time.Duration
AWSEvaluateTargetHealth bool AWSEvaluateTargetHealth bool
AWSAPIRetries int AWSAPIRetries int
AzureConfigFile string AzureConfigFile string
AzureResourceGroup string AzureResourceGroup string
CloudflareProxied bool CloudflareProxied bool
CloudflareZonesPerPage int CloudflareZonesPerPage int
RcodezeroTXTEncrypt bool RcodezeroTXTEncrypt bool
InfobloxGridHost string InfobloxGridHost string
InfobloxWapiPort int InfobloxWapiPort int
InfobloxWapiUsername string InfobloxWapiUsername string
InfobloxWapiPassword string InfobloxWapiPassword string
InfobloxWapiVersion string InfobloxWapiVersion string
InfobloxSSLVerify bool InfobloxSSLVerify bool
InfobloxView string InfobloxView string
DynCustomerName string DynCustomerName string
DynUsername string DynUsername string
DynPassword string DynPassword string
DynMinTTLSeconds int DynMinTTLSeconds int
OCIConfigFile string OCIConfigFile string
InMemoryZones []string InMemoryZones []string
PDNSServer string PDNSServer string
PDNSAPIKey string PDNSAPIKey string
PDNSTLSEnabled bool PDNSTLSEnabled bool
TLSCA string TLSCA string
TLSClientCert string TLSClientCert string
TLSClientCertKey string TLSClientCertKey string
Policy string Policy string
Registry string Registry string
TXTOwnerID string TXTOwnerID string
TXTPrefix string TXTPrefix string
Interval time.Duration Interval time.Duration
Once bool Once bool
DryRun bool DryRun bool
LogFormat string LogFormat string
MetricsAddress string MetricsAddress string
LogLevel string LogLevel string
TXTCacheInterval time.Duration TXTCacheInterval time.Duration
ExoscaleEndpoint string ExoscaleEndpoint string
ExoscaleAPIKey string ExoscaleAPIKey string
ExoscaleAPISecret string ExoscaleAPISecret string
CRDSourceAPIVersion string CRDSourceAPIVersion string
CRDSourceKind string CRDSourceKind string
ServiceTypeFilter []string ServiceTypeFilter []string
RFC2136Host string RFC2136Host string
RFC2136Port int RFC2136Port int
RFC2136Zone string RFC2136Zone string
RFC2136Insecure bool RFC2136Insecure bool
RFC2136TSIGKeyName string RFC2136TSIGKeyName string
RFC2136TSIGSecret string RFC2136TSIGSecret string
RFC2136TSIGSecretAlg string RFC2136TSIGSecretAlg string
RFC2136TAXFR bool RFC2136TAXFR bool
} }
var defaultConfig = &Config{ var defaultConfig = &Config{
Master: "", Master: "",
KubeConfig: "", KubeConfig: "",
RequestTimeout: time.Second * 30, RequestTimeout: time.Second * 30,
IstioIngressGateway: "istio-system/istio-ingressgateway", IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway"},
Sources: nil, Sources: nil,
Namespace: "", Namespace: "",
AnnotationFilter: "", AnnotationFilter: "",
FQDNTemplate: "", FQDNTemplate: "",
CombineFQDNAndAnnotation: false, CombineFQDNAndAnnotation: false,
IgnoreHostnameAnnotation: false, IgnoreHostnameAnnotation: false,
Compatibility: "", Compatibility: "",
PublishInternal: false, PublishInternal: false,
PublishHostIP: false, PublishHostIP: false,
ConnectorSourceServer: "localhost:8080", ConnectorSourceServer: "localhost:8080",
Provider: "", Provider: "",
GoogleProject: "", GoogleProject: "",
DomainFilter: []string{}, DomainFilter: []string{},
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
AWSZoneType: "", AWSZoneType: "",
AWSZoneTagFilter: []string{}, AWSZoneTagFilter: []string{},
AWSAssumeRole: "", AWSAssumeRole: "",
AWSBatchChangeSize: 1000, AWSBatchChangeSize: 1000,
AWSBatchChangeInterval: time.Second, AWSBatchChangeInterval: time.Second,
AWSEvaluateTargetHealth: true, AWSEvaluateTargetHealth: true,
AWSAPIRetries: 3, AWSAPIRetries: 3,
AzureConfigFile: "/etc/kubernetes/azure.json", AzureConfigFile: "/etc/kubernetes/azure.json",
AzureResourceGroup: "", AzureResourceGroup: "",
CloudflareProxied: false, CloudflareProxied: false,
CloudflareZonesPerPage: 50, CloudflareZonesPerPage: 50,
RcodezeroTXTEncrypt: false, RcodezeroTXTEncrypt: false,
InfobloxGridHost: "", InfobloxGridHost: "",
InfobloxWapiPort: 443, InfobloxWapiPort: 443,
InfobloxWapiUsername: "admin", InfobloxWapiUsername: "admin",
InfobloxWapiPassword: "", InfobloxWapiPassword: "",
InfobloxWapiVersion: "2.3.1", InfobloxWapiVersion: "2.3.1",
InfobloxSSLVerify: true, InfobloxSSLVerify: true,
InfobloxView: "", InfobloxView: "",
OCIConfigFile: "/etc/kubernetes/oci.yaml", OCIConfigFile: "/etc/kubernetes/oci.yaml",
InMemoryZones: []string{}, InMemoryZones: []string{},
PDNSServer: "http://localhost:8081", PDNSServer: "http://localhost:8081",
PDNSAPIKey: "", PDNSAPIKey: "",
PDNSTLSEnabled: false, PDNSTLSEnabled: false,
TLSCA: "", TLSCA: "",
TLSClientCert: "", TLSClientCert: "",
TLSClientCertKey: "", TLSClientCertKey: "",
Policy: "sync", Policy: "sync",
Registry: "txt", Registry: "txt",
TXTOwnerID: "default", TXTOwnerID: "default",
TXTPrefix: "", TXTPrefix: "",
TXTCacheInterval: 0, TXTCacheInterval: 0,
Interval: time.Minute, Interval: time.Minute,
Once: false, Once: false,
DryRun: false, DryRun: false,
LogFormat: "text", LogFormat: "text",
MetricsAddress: ":7979", MetricsAddress: ":7979",
LogLevel: logrus.InfoLevel.String(), LogLevel: logrus.InfoLevel.String(),
ExoscaleEndpoint: "https://api.exoscale.ch/dns", ExoscaleEndpoint: "https://api.exoscale.ch/dns",
ExoscaleAPIKey: "", ExoscaleAPIKey: "",
ExoscaleAPISecret: "", ExoscaleAPISecret: "",
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
CRDSourceKind: "DNSEndpoint", CRDSourceKind: "DNSEndpoint",
ServiceTypeFilter: []string{}, ServiceTypeFilter: []string{},
RFC2136Host: "", RFC2136Host: "",
RFC2136Port: 0, RFC2136Port: 0,
RFC2136Zone: "", RFC2136Zone: "",
RFC2136Insecure: false, RFC2136Insecure: false,
RFC2136TSIGKeyName: "", RFC2136TSIGKeyName: "",
RFC2136TSIGSecret: "", RFC2136TSIGSecret: "",
RFC2136TSIGSecretAlg: "", RFC2136TSIGSecretAlg: "",
RFC2136TAXFR: true, RFC2136TAXFR: true,
} }
// NewConfig returns new Config object // NewConfig returns new Config object
@ -229,7 +229,7 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("request-timeout", "Request timeout when calling Kubernetes APIs. 0s means no timeout").Default(defaultConfig.RequestTimeout.String()).DurationVar(&cfg.RequestTimeout) app.Flag("request-timeout", "Request timeout when calling Kubernetes APIs. 0s means no timeout").Default(defaultConfig.RequestTimeout.String()).DurationVar(&cfg.RequestTimeout)
// Flags related to Istio // Flags related to Istio
app.Flag("istio-ingress-gateway", "The fully-qualified name of the Istio ingress gateway service (default: istio-system/istio-ingressgateway)").Default(defaultConfig.IstioIngressGateway).StringVar(&cfg.IstioIngressGateway) app.Flag("istio-ingress-gateway", "The fully-qualified name of the Istio ingress gateway service. Flag can be specified multiple times (default: istio-system/istio-ingressgateway)").Default("istio-system/istio-ingressgateway").StringsVar(&cfg.IstioIngressGatewayServices)
// Flags related to processing sources // Flags related to processing sources
app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, fake, connector, istio-gateway, crd").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "istio-gateway", "fake", "connector", "crd") app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, fake, connector, istio-gateway, crd").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "istio-gateway", "fake", "connector", "crd")

View File

@ -29,120 +29,177 @@ import (
var ( var (
minimalConfig = &Config{ minimalConfig = &Config{
Master: "", Master: "",
KubeConfig: "", KubeConfig: "",
RequestTimeout: time.Second * 30, RequestTimeout: time.Second * 30,
IstioIngressGateway: "istio-system/istio-ingressgateway", IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway"},
Sources: []string{"service"}, Sources: []string{"service"},
Namespace: "", Namespace: "",
FQDNTemplate: "", FQDNTemplate: "",
Compatibility: "", Compatibility: "",
Provider: "google", Provider: "google",
GoogleProject: "", GoogleProject: "",
DomainFilter: []string{""}, DomainFilter: []string{""},
ZoneIDFilter: []string{""}, ZoneIDFilter: []string{""},
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
AWSZoneType: "", AWSZoneType: "",
AWSZoneTagFilter: []string{""}, AWSZoneTagFilter: []string{""},
AWSAssumeRole: "", AWSAssumeRole: "",
AWSBatchChangeSize: 1000, AWSBatchChangeSize: 1000,
AWSBatchChangeInterval: time.Second, AWSBatchChangeInterval: time.Second,
AWSEvaluateTargetHealth: true, AWSEvaluateTargetHealth: true,
AWSAPIRetries: 3, AWSAPIRetries: 3,
AzureConfigFile: "/etc/kubernetes/azure.json", AzureConfigFile: "/etc/kubernetes/azure.json",
AzureResourceGroup: "", AzureResourceGroup: "",
CloudflareProxied: false, CloudflareProxied: false,
CloudflareZonesPerPage: 50, CloudflareZonesPerPage: 50,
InfobloxGridHost: "", InfobloxGridHost: "",
InfobloxWapiPort: 443, InfobloxWapiPort: 443,
InfobloxWapiUsername: "admin", InfobloxWapiUsername: "admin",
InfobloxWapiPassword: "", InfobloxWapiPassword: "",
InfobloxWapiVersion: "2.3.1", InfobloxWapiVersion: "2.3.1",
InfobloxView: "", InfobloxView: "",
InfobloxSSLVerify: true, InfobloxSSLVerify: true,
OCIConfigFile: "/etc/kubernetes/oci.yaml", OCIConfigFile: "/etc/kubernetes/oci.yaml",
InMemoryZones: []string{""}, InMemoryZones: []string{""},
PDNSServer: "http://localhost:8081", PDNSServer: "http://localhost:8081",
PDNSAPIKey: "", PDNSAPIKey: "",
Policy: "sync", Policy: "sync",
Registry: "txt", Registry: "txt",
TXTOwnerID: "default", TXTOwnerID: "default",
TXTPrefix: "", TXTPrefix: "",
TXTCacheInterval: 0, TXTCacheInterval: 0,
Interval: time.Minute, Interval: time.Minute,
Once: false, Once: false,
DryRun: false, DryRun: false,
LogFormat: "text", LogFormat: "text",
MetricsAddress: ":7979", MetricsAddress: ":7979",
LogLevel: logrus.InfoLevel.String(), LogLevel: logrus.InfoLevel.String(),
ConnectorSourceServer: "localhost:8080", ConnectorSourceServer: "localhost:8080",
ExoscaleEndpoint: "https://api.exoscale.ch/dns", ExoscaleEndpoint: "https://api.exoscale.ch/dns",
ExoscaleAPIKey: "", ExoscaleAPIKey: "",
ExoscaleAPISecret: "", ExoscaleAPISecret: "",
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
CRDSourceKind: "DNSEndpoint", CRDSourceKind: "DNSEndpoint",
RcodezeroTXTEncrypt: false, RcodezeroTXTEncrypt: false,
} }
overriddenConfig = &Config{ overriddenConfig = &Config{
Master: "http://127.0.0.1:8080", Master: "http://127.0.0.1:8080",
KubeConfig: "/some/path", KubeConfig: "/some/path",
RequestTimeout: time.Second * 77, RequestTimeout: time.Second * 77,
IstioIngressGateway: "istio-other/istio-otheringressgateway", IstioIngressGatewayServices: []string{"istio-other/istio-otheringressgateway"},
Sources: []string{"service", "ingress", "connector"}, Sources: []string{"service", "ingress", "connector"},
Namespace: "namespace", Namespace: "namespace",
IgnoreHostnameAnnotation: true, IgnoreHostnameAnnotation: true,
FQDNTemplate: "{{.Name}}.service.example.com", FQDNTemplate: "{{.Name}}.service.example.com",
Compatibility: "mate", Compatibility: "mate",
Provider: "google", Provider: "google",
GoogleProject: "project", GoogleProject: "project",
DomainFilter: []string{"example.org", "company.com"}, DomainFilter: []string{"example.org", "company.com"},
ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"}, ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"},
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
AWSZoneType: "private", AWSZoneType: "private",
AWSZoneTagFilter: []string{"tag=foo"}, AWSZoneTagFilter: []string{"tag=foo"},
AWSAssumeRole: "some-other-role", AWSAssumeRole: "some-other-role",
AWSBatchChangeSize: 100, AWSBatchChangeSize: 100,
AWSBatchChangeInterval: time.Second * 2, AWSBatchChangeInterval: time.Second * 2,
AWSEvaluateTargetHealth: false, AWSEvaluateTargetHealth: false,
AWSAPIRetries: 13, AWSAPIRetries: 13,
AzureConfigFile: "azure.json", AzureConfigFile: "azure.json",
AzureResourceGroup: "arg", AzureResourceGroup: "arg",
CloudflareProxied: true, CloudflareProxied: true,
CloudflareZonesPerPage: 20, CloudflareZonesPerPage: 20,
InfobloxGridHost: "127.0.0.1", InfobloxGridHost: "127.0.0.1",
InfobloxWapiPort: 8443, InfobloxWapiPort: 8443,
InfobloxWapiUsername: "infoblox", InfobloxWapiUsername: "infoblox",
InfobloxWapiPassword: "infoblox", InfobloxWapiPassword: "infoblox",
InfobloxWapiVersion: "2.6.1", InfobloxWapiVersion: "2.6.1",
InfobloxView: "internal", InfobloxView: "internal",
InfobloxSSLVerify: false, InfobloxSSLVerify: false,
OCIConfigFile: "oci.yaml", OCIConfigFile: "oci.yaml",
InMemoryZones: []string{"example.org", "company.com"}, InMemoryZones: []string{"example.org", "company.com"},
PDNSServer: "http://ns.example.com:8081", PDNSServer: "http://ns.example.com:8081",
PDNSAPIKey: "some-secret-key", PDNSAPIKey: "some-secret-key",
PDNSTLSEnabled: true, PDNSTLSEnabled: true,
TLSCA: "/path/to/ca.crt", TLSCA: "/path/to/ca.crt",
TLSClientCert: "/path/to/cert.pem", TLSClientCert: "/path/to/cert.pem",
TLSClientCertKey: "/path/to/key.pem", TLSClientCertKey: "/path/to/key.pem",
Policy: "upsert-only", Policy: "upsert-only",
Registry: "noop", Registry: "noop",
TXTOwnerID: "owner-1", TXTOwnerID: "owner-1",
TXTPrefix: "associated-txt-record", TXTPrefix: "associated-txt-record",
TXTCacheInterval: 12 * time.Hour, TXTCacheInterval: 12 * time.Hour,
Interval: 10 * time.Minute, Interval: 10 * time.Minute,
Once: true, Once: true,
DryRun: true, DryRun: true,
LogFormat: "json", LogFormat: "json",
MetricsAddress: "127.0.0.1:9099", MetricsAddress: "127.0.0.1:9099",
LogLevel: logrus.DebugLevel.String(), LogLevel: logrus.DebugLevel.String(),
ConnectorSourceServer: "localhost:8081", ConnectorSourceServer: "localhost:8081",
ExoscaleEndpoint: "https://api.foo.ch/dns", ExoscaleEndpoint: "https://api.foo.ch/dns",
ExoscaleAPIKey: "1", ExoscaleAPIKey: "1",
ExoscaleAPISecret: "2", ExoscaleAPISecret: "2",
CRDSourceAPIVersion: "test.k8s.io/v1alpha1", CRDSourceAPIVersion: "test.k8s.io/v1alpha1",
CRDSourceKind: "Endpoint", CRDSourceKind: "Endpoint",
RcodezeroTXTEncrypt: true, RcodezeroTXTEncrypt: true,
}
// minimal config with istio gateway source and multiple ingressgateway load balancer services
multipleIstioIngressGatewaysConfig = &Config{
Master: "",
KubeConfig: "",
RequestTimeout: time.Second * 30,
IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway", "istio-other/istio-otheringressgateway"},
Sources: []string{"istio-gateway"},
Namespace: "",
FQDNTemplate: "",
Compatibility: "",
Provider: "google",
GoogleProject: "",
DomainFilter: []string{""},
ZoneIDFilter: []string{""},
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
AWSZoneType: "",
AWSZoneTagFilter: []string{""},
AWSAssumeRole: "",
AWSBatchChangeSize: 1000,
AWSBatchChangeInterval: time.Second,
AWSEvaluateTargetHealth: true,
AWSAPIRetries: 3,
AzureConfigFile: "/etc/kubernetes/azure.json",
AzureResourceGroup: "",
CloudflareProxied: false,
CloudflareZonesPerPage: 50,
InfobloxGridHost: "",
InfobloxWapiPort: 443,
InfobloxWapiUsername: "admin",
InfobloxWapiPassword: "",
InfobloxWapiVersion: "2.3.1",
InfobloxView: "",
InfobloxSSLVerify: true,
OCIConfigFile: "/etc/kubernetes/oci.yaml",
InMemoryZones: []string{""},
PDNSServer: "http://localhost:8081",
PDNSAPIKey: "",
Policy: "sync",
Registry: "txt",
TXTOwnerID: "default",
TXTPrefix: "",
TXTCacheInterval: 0,
Interval: time.Minute,
Once: false,
DryRun: false,
LogFormat: "text",
MetricsAddress: ":7979",
LogLevel: logrus.InfoLevel.String(),
ConnectorSourceServer: "localhost:8080",
ExoscaleEndpoint: "https://api.exoscale.ch/dns",
ExoscaleAPIKey: "",
ExoscaleAPISecret: "",
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
CRDSourceKind: "DNSEndpoint",
RcodezeroTXTEncrypt: false,
} }
) )
@ -295,6 +352,27 @@ func TestParseFlags(t *testing.T) {
}, },
expected: overriddenConfig, expected: overriddenConfig,
}, },
{
title: "istio config with 2 ingressgateways",
args: []string{
"--provider=google",
"--source=istio-gateway",
"--istio-ingress-gateway=istio-system/istio-ingressgateway",
"--istio-ingress-gateway=istio-other/istio-otheringressgateway",
},
envVars: map[string]string{},
expected: multipleIstioIngressGatewaysConfig,
},
{
title: "override everything via environment variables with multiple istio ingress gateway load balancer services",
args: []string{},
envVars: map[string]string{
"EXTERNAL_DNS_PROVIDER": "google",
"EXTERNAL_DNS_SOURCE": "istio-gateway",
"EXTERNAL_DNS_ISTIO_INGRESS_GATEWAY": "istio-system/istio-ingressgateway\nistio-other/istio-otheringressgateway",
},
expected: multipleIstioIngressGatewaysConfig,
},
} { } {
t.Run(ti.title, func(t *testing.T) { t.Run(ti.title, func(t *testing.T) {
originalEnv := setEnv(t, ti.envVars) originalEnv := setEnv(t, ti.envVars)

View File

@ -38,22 +38,21 @@ import (
// The gateway implementation uses the spec.servers.hosts values for the hostnames. // The gateway implementation uses the spec.servers.hosts values for the hostnames.
// Use targetAnnotationKey to explicitly set Endpoint. // Use targetAnnotationKey to explicitly set Endpoint.
type gatewaySource struct { type gatewaySource struct {
kubeClient kubernetes.Interface kubeClient kubernetes.Interface
istioClient istiomodel.ConfigStore istioClient istiomodel.ConfigStore
istioNamespace string istioIngressGatewayServices []string
istioIngressGatewayName string namespace string
namespace string annotationFilter string
annotationFilter string fqdnTemplate *template.Template
fqdnTemplate *template.Template combineFQDNAnnotation bool
combineFQDNAnnotation bool ignoreHostnameAnnotation bool
ignoreHostnameAnnotation bool
} }
// NewIstioGatewaySource creates a new gatewaySource with the given config. // NewIstioGatewaySource creates a new gatewaySource with the given config.
func NewIstioGatewaySource( func NewIstioGatewaySource(
kubeClient kubernetes.Interface, kubeClient kubernetes.Interface,
istioClient istiomodel.ConfigStore, istioClient istiomodel.ConfigStore,
istioIngressGateway string, istioIngressGatewayServices []string,
namespace string, namespace string,
annotationFilter string, annotationFilter string,
fqdnTemplate string, fqdnTemplate string,
@ -64,9 +63,10 @@ func NewIstioGatewaySource(
tmpl *template.Template tmpl *template.Template
err error err error
) )
istioNamespace, istioIngressGatewayName, err := parseIngressGateway(istioIngressGateway) for _, lbService := range istioIngressGatewayServices {
if err != nil { if _, _, err = parseIngressGateway(lbService); err != nil {
return nil, err return nil, err
}
} }
if fqdnTemplate != "" { if fqdnTemplate != "" {
@ -79,15 +79,14 @@ func NewIstioGatewaySource(
} }
return &gatewaySource{ return &gatewaySource{
kubeClient: kubeClient, kubeClient: kubeClient,
istioClient: istioClient, istioClient: istioClient,
istioNamespace: istioNamespace, istioIngressGatewayServices: istioIngressGatewayServices,
istioIngressGatewayName: istioIngressGatewayName, namespace: namespace,
namespace: namespace, annotationFilter: annotationFilter,
annotationFilter: annotationFilter, fqdnTemplate: tmpl,
fqdnTemplate: tmpl, combineFQDNAnnotation: combineFqdnAnnotation,
combineFQDNAnnotation: combineFqdnAnnotation, ignoreHostnameAnnotation: ignoreHostnameAnnotation,
ignoreHostnameAnnotation: ignoreHostnameAnnotation,
}, nil }, nil
} }
@ -169,7 +168,7 @@ func (sc *gatewaySource) endpointsFromTemplate(config *istiomodel.Config) ([]*en
targets := getTargetsFromTargetAnnotation(config.Annotations) targets := getTargetsFromTargetAnnotation(config.Annotations)
if len(targets) == 0 { if len(targets) == 0 {
targets, err = sc.targetsFromIstioIngressStatus() targets, err = sc.targetsFromIstioIngressGatewayServices()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -224,16 +223,22 @@ func (sc *gatewaySource) setResourceLabel(config istiomodel.Config, endpoints []
} }
} }
func (sc *gatewaySource) targetsFromIstioIngressStatus() (targets endpoint.Targets, err error) { func (sc *gatewaySource) targetsFromIstioIngressGatewayServices() (targets endpoint.Targets, err error) {
if svc, e := sc.kubeClient.CoreV1().Services(sc.istioNamespace).Get(sc.istioIngressGatewayName, metav1.GetOptions{}); e != nil { for _, lbService := range sc.istioIngressGatewayServices {
err = e lbNamespace, lbName, err := parseIngressGateway(lbService)
} else { if err != nil {
for _, lb := range svc.Status.LoadBalancer.Ingress { return nil, err
if lb.IP != "" { }
targets = append(targets, lb.IP) if svc, err := sc.kubeClient.CoreV1().Services(lbNamespace).Get(lbName, metav1.GetOptions{}); err != nil {
} log.Warn(err)
if lb.Hostname != "" { } else {
targets = append(targets, lb.Hostname) for _, lb := range svc.Status.LoadBalancer.Ingress {
if lb.IP != "" {
targets = append(targets, lb.IP)
}
if lb.Hostname != "" {
targets = append(targets, lb.Hostname)
}
} }
} }
} }
@ -253,7 +258,7 @@ func (sc *gatewaySource) endpointsFromGatewayConfig(config istiomodel.Config) ([
targets := getTargetsFromTargetAnnotation(config.Annotations) targets := getTargetsFromTargetAnnotation(config.Annotations)
if len(targets) == 0 { if len(targets) == 0 {
targets, err = sc.targetsFromIstioIngressStatus() targets, err = sc.targetsFromIstioIngressGatewayServices()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -43,9 +43,9 @@ var gatewayType = istiomodel.Gateway.Type
type GatewaySuite struct { type GatewaySuite struct {
suite.Suite suite.Suite
source Source source Source
ingress *v1.Service lbServices []*v1.Service
config istiomodel.Config config istiomodel.Config
} }
func (suite *GatewaySuite) SetupTest() { func (suite *GatewaySuite) SetupTest() {
@ -53,17 +53,30 @@ func (suite *GatewaySuite) SetupTest() {
fakeIstioClient := NewFakeConfigStore() fakeIstioClient := NewFakeConfigStore()
var err error var err error
suite.ingress = (fakeIngressGateway{ suite.lbServices = []*v1.Service{
ips: []string{"8.8.8.8"}, (fakeIngressGatewayService{
hostnames: []string{"v1"}, ips: []string{"8.8.8.8"},
}).Service() hostnames: []string{"v1"},
_, err = fakeKubernetesClient.CoreV1().Services(suite.ingress.Namespace).Create(suite.ingress) namespace: "istio-system",
suite.NoError(err, "should succeed") name: "istio-gateway1",
}).Service(),
(fakeIngressGatewayService{
ips: []string{"1.1.1.1"},
hostnames: []string{"v42"},
namespace: "istio-other",
name: "istio-gateway2",
}).Service(),
}
for _, loadBalancer := range suite.lbServices {
_, err = fakeKubernetesClient.CoreV1().Services(loadBalancer.Namespace).Create(loadBalancer)
suite.NoError(err, "should succeed")
}
suite.source, err = NewIstioGatewaySource( suite.source, err = NewIstioGatewaySource(
fakeKubernetesClient, fakeKubernetesClient,
fakeIstioClient, fakeIstioClient,
"istio-system/istio-ingressgateway", []string{"istio-system/istio-ingressgateway"},
"default", "default",
"", "",
"{{.Name}}", "{{.Name}}",
@ -137,7 +150,7 @@ func TestNewIstioGatewaySource(t *testing.T) {
_, err := NewIstioGatewaySource( _, err := NewIstioGatewaySource(
fake.NewSimpleClientset(), fake.NewSimpleClientset(),
NewFakeConfigStore(), NewFakeConfigStore(),
"istio-system/istio-ingressgateway", []string{"istio-system/istio-ingressgateway"},
"", "",
ti.annotationFilter, ti.annotationFilter,
ti.fqdnTemplate, ti.fqdnTemplate,
@ -155,15 +168,17 @@ func TestNewIstioGatewaySource(t *testing.T) {
func testEndpointsFromGatewayConfig(t *testing.T) { func testEndpointsFromGatewayConfig(t *testing.T) {
for _, ti := range []struct { for _, ti := range []struct {
title string title string
ingress fakeIngressGateway lbServices []fakeIngressGatewayService
config fakeGatewayConfig config fakeGatewayConfig
expected []*endpoint.Endpoint expected []*endpoint.Endpoint
}{ }{
{ {
title: "one rule.host one lb.hostname", title: "one rule.host one lb.hostname",
ingress: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
hostnames: []string{"lb.com"}, // Kubernetes omits the trailing dot {
hostnames: []string{"lb.com"}, // Kubernetes omits the trailing dot
},
}, },
config: fakeGatewayConfig{ config: fakeGatewayConfig{
dnsnames: [][]string{ dnsnames: [][]string{
@ -179,8 +194,10 @@ func testEndpointsFromGatewayConfig(t *testing.T) {
}, },
{ {
title: "one rule.host one lb.IP", title: "one rule.host one lb.IP",
ingress: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
config: fakeGatewayConfig{ config: fakeGatewayConfig{
dnsnames: [][]string{ dnsnames: [][]string{
@ -196,9 +213,11 @@ func testEndpointsFromGatewayConfig(t *testing.T) {
}, },
{ {
title: "one rule.host two lb.IP and two lb.Hostname", title: "one rule.host two lb.IP and two lb.Hostname",
ingress: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8", "127.0.0.1"}, {
hostnames: []string{"elb.com", "alb.com"}, ips: []string{"8.8.8.8", "127.0.0.1"},
hostnames: []string{"elb.com", "alb.com"},
},
}, },
config: fakeGatewayConfig{ config: fakeGatewayConfig{
dnsnames: [][]string{ dnsnames: [][]string{
@ -218,9 +237,11 @@ func testEndpointsFromGatewayConfig(t *testing.T) {
}, },
{ {
title: "no rule.host", title: "no rule.host",
ingress: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8", "127.0.0.1"}, {
hostnames: []string{"elb.com", "alb.com"}, ips: []string{"8.8.8.8", "127.0.0.1"},
hostnames: []string{"elb.com", "alb.com"},
},
}, },
config: fakeGatewayConfig{ config: fakeGatewayConfig{
dnsnames: [][]string{}, dnsnames: [][]string{},
@ -229,9 +250,11 @@ func testEndpointsFromGatewayConfig(t *testing.T) {
}, },
{ {
title: "one empty rule.host", title: "one empty rule.host",
ingress: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8", "127.0.0.1"}, {
hostnames: []string{"elb.com", "alb.com"}, ips: []string{"8.8.8.8", "127.0.0.1"},
hostnames: []string{"elb.com", "alb.com"},
},
}, },
config: fakeGatewayConfig{ config: fakeGatewayConfig{
dnsnames: [][]string{ dnsnames: [][]string{
@ -241,8 +264,8 @@ func testEndpointsFromGatewayConfig(t *testing.T) {
expected: []*endpoint.Endpoint{}, expected: []*endpoint.Endpoint{},
}, },
{ {
title: "no targets", title: "no targets",
ingress: fakeIngressGateway{}, lbServices: []fakeIngressGatewayService{{}},
config: fakeGatewayConfig{ config: fakeGatewayConfig{
dnsnames: [][]string{ dnsnames: [][]string{
{""}, {""},
@ -250,9 +273,35 @@ func testEndpointsFromGatewayConfig(t *testing.T) {
}, },
expected: []*endpoint.Endpoint{}, expected: []*endpoint.Endpoint{},
}, },
{
title: "one gateway, two ingressgateway loadbalancer hostnames",
lbServices: []fakeIngressGatewayService{
{
hostnames: []string{"lb.com"},
namespace: "istio-other",
name: "gateway1",
},
{
hostnames: []string{"lb2.com"},
namespace: "istio-other",
name: "gateway2",
},
},
config: fakeGatewayConfig{
dnsnames: [][]string{
{"foo.bar"}, // Kubernetes requires removal of trailing dot
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "foo.bar",
Targets: endpoint.Targets{"lb.com", "lb2.com"},
},
},
},
} { } {
t.Run(ti.title, func(t *testing.T) { t.Run(ti.title, func(t *testing.T) {
if source, err := newTestGatewaySource(ti.ingress.Service()); err != nil { if source, err := newTestGatewaySource(ti.lbServices); err != nil {
require.NoError(t, err) require.NoError(t, err)
} else if endpoints, err := source.endpointsFromGatewayConfig(ti.config.Config()); err != nil { } else if endpoints, err := source.endpointsFromGatewayConfig(ti.config.Config()); err != nil {
require.NoError(t, err) require.NoError(t, err)
@ -269,7 +318,7 @@ func testGatewayEndpoints(t *testing.T) {
title string title string
targetNamespace string targetNamespace string
annotationFilter string annotationFilter string
ingressGateway fakeIngressGateway lbServices []fakeIngressGatewayService
configItems []fakeGatewayConfig configItems []fakeGatewayConfig
expected []*endpoint.Endpoint expected []*endpoint.Endpoint
expectError bool expectError bool
@ -282,11 +331,13 @@ func testGatewayEndpoints(t *testing.T) {
targetNamespace: "", targetNamespace: "",
}, },
{ {
title: "two simple gateways", title: "two simple gateways, one ingressgateway loadbalancer service",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
hostnames: []string{"lb.com"}, ips: []string{"8.8.8.8"},
hostnames: []string{"lb.com"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -320,11 +371,13 @@ func testGatewayEndpoints(t *testing.T) {
}, },
}, },
{ {
title: "two simple gateways on different namespaces", title: "two simple gateways on different namespaces, one ingressgateway loadbalancer service",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
hostnames: []string{"lb.com"}, ips: []string{"8.8.8.8"},
hostnames: []string{"lb.com"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -358,11 +411,13 @@ func testGatewayEndpoints(t *testing.T) {
}, },
}, },
{ {
title: "two simple gateways on different namespaces with target namespace", title: "two simple gateways on different namespaces and a target namespace, one ingressgateway loadbalancer service",
targetNamespace: "testing1", targetNamespace: "testing1",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
hostnames: []string{"lb.com"}, ips: []string{"8.8.8.8"},
hostnames: []string{"lb.com"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -391,8 +446,10 @@ func testGatewayEndpoints(t *testing.T) {
title: "valid matching annotation filter expression", title: "valid matching annotation filter expression",
targetNamespace: "", targetNamespace: "",
annotationFilter: "kubernetes.io/gateway.class in (alb, nginx)", annotationFilter: "kubernetes.io/gateway.class in (alb, nginx)",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -415,8 +472,10 @@ func testGatewayEndpoints(t *testing.T) {
title: "valid non-matching annotation filter expression", title: "valid non-matching annotation filter expression",
targetNamespace: "", targetNamespace: "",
annotationFilter: "kubernetes.io/gateway.class in (alb, nginx)", annotationFilter: "kubernetes.io/gateway.class in (alb, nginx)",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -434,8 +493,10 @@ func testGatewayEndpoints(t *testing.T) {
title: "invalid annotation filter expression", title: "invalid annotation filter expression",
targetNamespace: "", targetNamespace: "",
annotationFilter: "kubernetes.io/gateway.name in (a b)", annotationFilter: "kubernetes.io/gateway.name in (a b)",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -454,8 +515,10 @@ func testGatewayEndpoints(t *testing.T) {
title: "valid matching annotation filter label", title: "valid matching annotation filter label",
targetNamespace: "", targetNamespace: "",
annotationFilter: "kubernetes.io/gateway.class=nginx", annotationFilter: "kubernetes.io/gateway.class=nginx",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -478,8 +541,10 @@ func testGatewayEndpoints(t *testing.T) {
title: "valid non-matching annotation filter label", title: "valid non-matching annotation filter label",
targetNamespace: "", targetNamespace: "",
annotationFilter: "kubernetes.io/gateway.class=nginx", annotationFilter: "kubernetes.io/gateway.class=nginx",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -496,8 +561,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "our controller type is dns-controller", title: "our controller type is dns-controller",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -519,8 +586,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "different controller types are ignored", title: "different controller types are ignored",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -537,9 +606,11 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "template for gateway if host is missing", title: "template for gateway if host is missing",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
hostnames: []string{"elb.com"}, ips: []string{"8.8.8.8"},
hostnames: []string{"elb.com"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -566,8 +637,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "another controller annotation skipped even with template", title: "another controller annotation skipped even with template",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -585,8 +658,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "multiple FQDN template hostnames", title: "multiple FQDN template hostnames",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -613,8 +688,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "multiple FQDN template hostnames", title: "multiple FQDN template hostnames",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -665,8 +742,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "gateway rules with annotation", title: "gateway rules with annotation",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -715,8 +794,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "gateway rules with hostname annotation", title: "gateway rules with hostname annotation",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"1.2.3.4"}, {
ips: []string{"1.2.3.4"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -744,8 +825,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "gateway rules with hostname annotation having multiple hostnames", title: "gateway rules with hostname annotation having multiple hostnames",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"1.2.3.4"}, {
ips: []string{"1.2.3.4"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -778,8 +861,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "gateway rules with hostname and target annotation", title: "gateway rules with hostname and target annotation",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{}, {
ips: []string{},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -808,8 +893,10 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "gateway rules with annotation and custom TTL", title: "gateway rules with annotation and custom TTL",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
ips: []string{"8.8.8.8"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -847,9 +934,11 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "template for gateway with annotation", title: "template for gateway with annotation",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{}, {
hostnames: []string{}, ips: []string{},
hostnames: []string{},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -899,9 +988,11 @@ func testGatewayEndpoints(t *testing.T) {
{ {
title: "Ingress with empty annotation", title: "Ingress with empty annotation",
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{}, {
hostnames: []string{}, ips: []string{},
hostnames: []string{},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -920,9 +1011,11 @@ func testGatewayEndpoints(t *testing.T) {
title: "ignore hostname annotations", title: "ignore hostname annotations",
ignoreHostnameAnnotation: true, ignoreHostnameAnnotation: true,
targetNamespace: "", targetNamespace: "",
ingressGateway: fakeIngressGateway{ lbServices: []fakeIngressGatewayService{
ips: []string{"8.8.8.8"}, {
hostnames: []string{"lb.com"}, ips: []string{"8.8.8.8"},
hostnames: []string{"lb.com"},
},
}, },
configItems: []fakeGatewayConfig{ configItems: []fakeGatewayConfig{
{ {
@ -969,10 +1062,17 @@ func testGatewayEndpoints(t *testing.T) {
} }
fakeKubernetesClient := fake.NewSimpleClientset() fakeKubernetesClient := fake.NewSimpleClientset()
ingressGatewayService := ti.ingressGateway.Service()
if _, err := fakeKubernetesClient.CoreV1().Services(ingressGatewayService.Namespace).Create(ingressGatewayService); err != nil { var fakeLoadBalancerList []string
require.NoError(t, err) for _, lb := range ti.lbServices {
lbService := lb.Service()
_, err := fakeKubernetesClient.CoreV1().Services(lbService.Namespace).Create(lbService)
if err != nil {
require.NoError(t, err)
}
fakeLoadBalancerList = append(fakeLoadBalancerList, lbService.Namespace+"/"+lbService.Name)
} }
fakeIstioClient := NewFakeConfigStore() fakeIstioClient := NewFakeConfigStore()
for _, config := range configs { for _, config := range configs {
_, err := fakeIstioClient.Create(config) _, err := fakeIstioClient.Create(config)
@ -982,7 +1082,7 @@ func testGatewayEndpoints(t *testing.T) {
gatewaySource, err := NewIstioGatewaySource( gatewaySource, err := NewIstioGatewaySource(
fakeKubernetesClient, fakeKubernetesClient,
fakeIstioClient, fakeIstioClient,
ingressGatewayService.Namespace+"/"+ingressGatewayService.Name, fakeLoadBalancerList,
ti.targetNamespace, ti.targetNamespace,
ti.annotationFilter, ti.annotationFilter,
ti.fqdnTemplate, ti.fqdnTemplate,
@ -1004,19 +1104,24 @@ func testGatewayEndpoints(t *testing.T) {
} }
// gateway specific helper functions // gateway specific helper functions
func newTestGatewaySource(ingress *v1.Service) (*gatewaySource, error) { func newTestGatewaySource(loadBalancerList []fakeIngressGatewayService) (*gatewaySource, error) {
fakeKubernetesClient := fake.NewSimpleClientset() fakeKubernetesClient := fake.NewSimpleClientset()
fakeIstioClient := NewFakeConfigStore() fakeIstioClient := NewFakeConfigStore()
_, err := fakeKubernetesClient.CoreV1().Services(ingress.Namespace).Create(ingress) var lbList []string
if err != nil { for _, lb := range loadBalancerList {
return nil, err lbService := lb.Service()
_, err := fakeKubernetesClient.CoreV1().Services(lbService.Namespace).Create(lbService)
if err != nil {
return nil, err
}
lbList = append(lbList, lbService.Namespace+"/"+lbService.Name)
} }
src, err := NewIstioGatewaySource( src, err := NewIstioGatewaySource(
fakeKubernetesClient, fakeKubernetesClient,
fakeIstioClient, fakeIstioClient,
"istio-system/istio-ingressgateway", lbList,
"default", "default",
"", "",
"{{.Name}}", "{{.Name}}",
@ -1035,16 +1140,18 @@ func newTestGatewaySource(ingress *v1.Service) (*gatewaySource, error) {
return gwsrc, nil return gwsrc, nil
} }
type fakeIngressGateway struct { type fakeIngressGatewayService struct {
ips []string ips []string
hostnames []string hostnames []string
namespace string
name string
} }
func (ig fakeIngressGateway) Service() *v1.Service { func (ig fakeIngressGatewayService) Service() *v1.Service {
svc := &v1.Service{ svc := &v1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: "istio-system", Namespace: ig.namespace,
Name: "istio-ingressgateway", Name: ig.name,
}, },
Status: v1.ServiceStatus{ Status: v1.ServiceStatus{
LoadBalancer: v1.LoadBalancerStatus{ LoadBalancer: v1.LoadBalancerStatus{

View File

@ -38,21 +38,21 @@ var ErrSourceNotFound = errors.New("source not found")
// Config holds shared configuration options for all Sources. // Config holds shared configuration options for all Sources.
type Config struct { type Config struct {
Namespace string Namespace string
AnnotationFilter string AnnotationFilter string
FQDNTemplate string FQDNTemplate string
CombineFQDNAndAnnotation bool CombineFQDNAndAnnotation bool
IgnoreHostnameAnnotation bool IgnoreHostnameAnnotation bool
Compatibility string Compatibility string
PublishInternal bool PublishInternal bool
PublishHostIP bool PublishHostIP bool
ConnectorServer string ConnectorServer string
CRDSourceAPIVersion string CRDSourceAPIVersion string
CRDSourceKind string CRDSourceKind string
KubeConfig string KubeConfig string
KubeMaster string KubeMaster string
ServiceTypeFilter []string ServiceTypeFilter []string
IstioIngressGateway string IstioIngressGatewayServices []string
} }
// ClientGenerator provides clients // ClientGenerator provides clients
@ -129,7 +129,7 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err
if err != nil { if err != nil {
return nil, err return nil, err
} }
return NewIstioGatewaySource(kubernetesClient, istioClient, cfg.IstioIngressGateway, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation) return NewIstioGatewaySource(kubernetesClient, istioClient, cfg.IstioIngressGatewayServices, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation)
case "fake": case "fake":
return NewFakeSource(cfg.FQDNTemplate) return NewFakeSource(cfg.FQDNTemplate)
case "connector": case "connector":

View File

@ -113,5 +113,5 @@ func TestByNames(t *testing.T) {
} }
var minimalConfig = &Config{ var minimalConfig = &Config{
IstioIngressGateway: "istio-system/istio-ingressgateway", IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway"},
} }