Skip to content

Commit

Permalink
Log the resolver used to obtain the local endpoint public IP
Browse files Browse the repository at this point in the history
...to aid in debugging.

Signed-off-by: Tom Pantelis <[email protected]>
  • Loading branch information
tpantelis committed Jan 7, 2025
1 parent 53ac157 commit 90d2137
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 25 deletions.
4 changes: 3 additions & 1 deletion pkg/endpoint/local_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,13 @@ func GetLocalSpec(ctx context.Context, submSpec *types.SubmarinerSpecification,
BackendConfig: backendConfig,
}

publicIP, err := getPublicIP(submSpec, k8sClient, backendConfig, airGappedDeployment)
publicIP, resolver, err := getPublicIP(submSpec, k8sClient, backendConfig, airGappedDeployment)
if err != nil {
return nil, errors.Wrap(err, "could not determine public IP")
}

logger.Infof("Obtained local endpoint public IP %q using resolver %q", publicIP, resolver)

endpointSpec.PublicIP = publicIP

if submSpec.HealthCheckEnabled && !globalnetEnabled {
Expand Down
26 changes: 14 additions & 12 deletions pkg/endpoint/public_ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func getPublicIPResolvers() string {

func getPublicIP(submSpec *types.SubmarinerSpecification, k8sClient kubernetes.Interface,
backendConfig map[string]string, airGapped bool,
) (string, error) {
) (string, string, error) {
// If the node is annotated with a public-ip, the same is used as the public-ip of local endpoint.
config, ok := backendConfig[v1.PublicIP]
if !ok {
Expand All @@ -77,13 +77,13 @@ func getPublicIP(submSpec *types.SubmarinerSpecification, k8sClient kubernetes.I
}

if airGapped {
ip, err := resolveIPInAirGappedDeployment(k8sClient, submSpec.Namespace, config)
ip, resolver, err := resolveIPInAirGappedDeployment(k8sClient, submSpec.Namespace, config)
if err != nil {
logger.Errorf(err, "Error resolving public IP in an air-gapped deployment, using empty value: %s", config)
return "", nil
return "", "", nil
}

return ip, nil
return ip, resolver, nil
}

resolvers := strings.Split(config, ",")
Expand All @@ -94,44 +94,46 @@ func getPublicIP(submSpec *types.SubmarinerSpecification, k8sClient kubernetes.I

parts := strings.Split(resolver, ":")
if len(parts) != 2 {
return "", errors.Errorf("invalid format for %q annotation: %q", v1.GatewayConfigPrefix+v1.PublicIP, config)
return "", "", errors.Errorf("invalid format for %q annotation: %q", v1.GatewayConfigPrefix+v1.PublicIP, config)
}

ip, err := resolvePublicIP(k8sClient, submSpec.Namespace, parts)
if err == nil {
return ip, nil
return ip, resolver, nil
}

// If this resolver failed, we log it, but we fall back to the next one
errs = append(errs, errors.Wrapf(err, "\nResolver[%q]", resolver))
}

if len(resolvers) > 0 {
return "", errors.Wrapf(k8serrors.NewAggregate(errs), "Unable to resolve public IP by any of the resolver methods")
return "", "", errors.Wrapf(k8serrors.NewAggregate(errs), "Unable to resolve public IP by any of the resolver methods")
}

return "", nil
return "", "", nil
}

func resolveIPInAirGappedDeployment(k8sClient kubernetes.Interface, namespace, config string) (string, error) {
func resolveIPInAirGappedDeployment(k8sClient kubernetes.Interface, namespace, config string) (string, string, error) {
resolvers := strings.Split(config, ",")

for _, resolver := range resolvers {
resolver = strings.Trim(resolver, " ")

parts := strings.Split(resolver, ":")
if len(parts) != 2 {
return "", errors.Errorf("invalid format for %q annotation: %q", v1.GatewayConfigPrefix+v1.PublicIP, config)
return "", "", errors.Errorf("invalid format for %q annotation: %q", v1.GatewayConfigPrefix+v1.PublicIP, config)
}

if parts[0] != v1.IPv4 {
continue
}

return resolvePublicIP(k8sClient, namespace, parts)
ip, err := resolvePublicIP(k8sClient, namespace, parts)

return ip, resolver, err
}

return "", nil
return "", "", nil
}

func resolvePublicIP(k8sClient kubernetes.Interface, namespace string, parts []string) (string, error) {
Expand Down
28 changes: 18 additions & 10 deletions pkg/endpoint/public_ip_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ var _ = Describe("public ip resolvers", func() {
It("should return the IP", func() {
backendConfig[publicIPConfig] = lbPublicIP
client := fake.NewClientset(serviceWithIngress(v1.LoadBalancerIngress{Hostname: "", IP: testIP}))
ip, err := getPublicIP(submSpec, client, backendConfig, false)
ip, resolver, err := getPublicIP(submSpec, client, backendConfig, false)
Expect(err).ToNot(HaveOccurred())
Expect(ip).To(Equal(testIP))
Expect(resolver).To(Equal(lbPublicIP))
})
})

Expand All @@ -94,9 +95,10 @@ var _ = Describe("public ip resolvers", func() {
Hostname: dnsHost,
IP: "",
}))
ip, err := getPublicIP(submSpec, client, backendConfig, false)
ip, resolver, err := getPublicIP(submSpec, client, backendConfig, false)
Expect(err).ToNot(HaveOccurred())
Expect(ip).To(Equal(testIPDNS))
Expect(resolver).To(Equal(lbPublicIP))
})
})

Expand All @@ -107,7 +109,7 @@ var _ = Describe("public ip resolvers", func() {
loadBalancerRetryConfig.Steps = 1
backendConfig[publicIPConfig] = lbPublicIP
client := fake.NewClientset(serviceWithIngress())
_, err := getPublicIP(submSpec, client, backendConfig, false)
_, _, err := getPublicIP(submSpec, client, backendConfig, false)
Expect(err).To(HaveOccurred())
})
})
Expand All @@ -116,59 +118,65 @@ var _ = Describe("public ip resolvers", func() {
It("should return the IP", func() {
backendConfig[publicIPConfig] = ipv4PublicIP
client := fake.NewClientset()
ip, err := getPublicIP(submSpec, client, backendConfig, false)
ip, resolver, err := getPublicIP(submSpec, client, backendConfig, false)
Expect(err).ToNot(HaveOccurred())
Expect(ip).To(Equal(testIP))
Expect(resolver).To(Equal(ipv4PublicIP))
})
})

When("an IPv4 entry specified in air-gapped deployment", func() {
It("should return the IP and not an empty value", func() {
backendConfig[publicIPConfig] = ipv4PublicIP
client := fake.NewClientset()
ip, err := getPublicIP(submSpec, client, backendConfig, true)
ip, resolver, err := getPublicIP(submSpec, client, backendConfig, true)
Expect(err).ToNot(HaveOccurred())
Expect(ip).To(Equal(testIP))
Expect(resolver).To(Equal(ipv4PublicIP))
})
})

When("a DNS entry specified", func() {
It("should return the IP", func() {
backendConfig[publicIPConfig] = "dns:" + dnsHost
client := fake.NewClientset()
ip, err := getPublicIP(submSpec, client, backendConfig, false)
ip, resolver, err := getPublicIP(submSpec, client, backendConfig, false)
Expect(err).ToNot(HaveOccurred())
Expect(ip).To(Equal(testIPDNS))
Expect(resolver).To(Equal(backendConfig[publicIPConfig]))
})
})

When("an API entry specified", func() {
It("should return some IP", func() {
backendConfig[publicIPConfig] = "api:4.icanhazip.com/"
client := fake.NewClientset()
ip, err := getPublicIP(submSpec, client, backendConfig, false)
ip, resolver, err := getPublicIP(submSpec, client, backendConfig, false)
Expect(err).ToNot(HaveOccurred())
Expect(net.ParseIP(ip)).NotTo(BeNil())
Expect(resolver).To(Equal(backendConfig[publicIPConfig]))
})
})

When("multiple entries are specified", func() {
It("should return the first working one", func() {
backendConfig[publicIPConfig] = ipv4PublicIP + ",dns:" + dnsHost
client := fake.NewClientset()
ip, err := getPublicIP(submSpec, client, backendConfig, false)
ip, resolver, err := getPublicIP(submSpec, client, backendConfig, false)
Expect(err).ToNot(HaveOccurred())
Expect(ip).To(Equal(testIP))
Expect(resolver).To(Equal(ipv4PublicIP))
})
})

When("multiple entries are specified and the first one doesn't succeed", func() {
It("should return the first working one", func() {
backendConfig[publicIPConfig] = "dns:thisdomaindoesntexistforsure.badbadbad,ipv4:" + testIP
backendConfig[publicIPConfig] = "dns:thisdomaindoesntexistforsure.badbadbad," + ipv4PublicIP
client := fake.NewClientset()
ip, err := getPublicIP(submSpec, client, backendConfig, false)
ip, resolver, err := getPublicIP(submSpec, client, backendConfig, false)
Expect(err).ToNot(HaveOccurred())
Expect(ip).To(Equal(testIP))
Expect(resolver).To(Equal(ipv4PublicIP))
})
})
})
Expand Down
5 changes: 3 additions & 2 deletions pkg/endpoint/public_ip_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,15 @@ func (p *PublicIPWatcher) Run(stopCh <-chan struct{}) {
func (p *PublicIPWatcher) syncPublicIP() {
localEndpointSpec := p.config.LocalEndpoint.Spec()

publicIP, err := getPublicIP(p.config.SubmSpec, p.config.K8sClient, localEndpointSpec.BackendConfig, false)
publicIP, resolver, err := getPublicIP(p.config.SubmSpec, p.config.K8sClient, localEndpointSpec.BackendConfig, false)
if err != nil {
logger.Warningf("Could not determine public IP of the gateway node %q: %v", localEndpointSpec.Hostname, err)
return
}

if localEndpointSpec.PublicIP != publicIP {
logger.Infof("Public IP changed for the Gateway, updating the local endpoint with publicIP %q", publicIP)
logger.Infof("Public IP changed for the Gateway, updating the local endpoint with public IP %q obtained from resolver %q",
publicIP, resolver)

if err := p.updateLocalEndpoint(publicIP); err != nil {
logger.Error(err, "Error updating the public IP for local endpoint")
Expand Down

0 comments on commit 90d2137

Please sign in to comment.