Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log the resolver used to obtain the local endpoint public IP #3255

Merged
merged 2 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading