Skip to content

Commit 5895224

Browse files
committed
fix: handle unresolved dev DNS updater hostnames
Signed-off-by: immanuwell <pchpr.00@list.ru>
1 parent c674687 commit 5895224

3 files changed

Lines changed: 150 additions & 9 deletions

File tree

src/utils/dev_dns_updater/BUILD.bazel

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# SPDX-License-Identifier: Apache-2.0
1616

1717
load("@io_bazel_rules_go//go:def.bzl", "go_library")
18-
load("//bazel:pl_build_system.bzl", "pl_go_binary")
18+
load("//bazel:pl_build_system.bzl", "pl_go_binary", "pl_go_test")
1919

2020
go_library(
2121
name = "dev_dns_updater_lib",
@@ -44,3 +44,14 @@ pl_go_binary(
4444
embed = [":dev_dns_updater_lib"],
4545
visibility = ["//src:__subpackages__"],
4646
)
47+
48+
pl_go_test(
49+
name = "dev_dns_updater_test",
50+
srcs = ["dev_dns_updater_test.go"],
51+
embed = [":dev_dns_updater_lib"],
52+
deps = [
53+
"@io_k8s_api//core/v1:core",
54+
"@io_k8s_apimachinery//pkg/apis/meta/v1:meta",
55+
"@io_k8s_apimachinery//pkg/watch",
56+
],
57+
)

src/utils/dev_dns_updater/dev_dns_updater.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var dnsEntriesByServiceCfg = map[string][]string{
5050
}
5151

5252
var dnsEntriesByService = map[string][]string{}
53+
var lookupIP = net.LookupIP
5354

5455
type svcInfo struct {
5556
SvcName string
@@ -59,7 +60,7 @@ type svcInfo struct {
5960
func init() {
6061
pflag.String("n", "plc-dev", "The namespace to watch (plc-dev) by default")
6162
pflag.String("domain-name", "dev.withpixie.dev", "The domain name to use")
62-
pflag.String("kubeconfig", filepath.Join(homeDir(), ".kube", "config"), "(optional) absolute path to the kubeconfig file")
63+
pflag.String("kubeconfig", defaultKubeconfig(), "(optional) absolute path to the kubeconfig file")
6364
}
6465

6566
func parseFlags() {
@@ -73,7 +74,11 @@ func parseFlags() {
7374
// getConfig gets the kubernetes rest config.
7475
func getConfig() *rest.Config {
7576
// use the current context in kubeconfig
76-
config, err := clientcmd.BuildConfigFromFlags("", viper.GetString("kubeconfig"))
77+
kubeconfig := viper.GetString("kubeconfig")
78+
if kubeconfig == "" {
79+
log.Fatal("Cannot determine homedir, pass in a kubeconfig location explicitly with --kubeconfig")
80+
}
81+
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
7782
if err != nil {
7883
log.WithError(err).Fatal("Could not build kubeconfig")
7984
}
@@ -91,12 +96,12 @@ func getClientset(config *rest.Config) *kubernetes.Clientset {
9196
return clientset
9297
}
9398

94-
func homeDir() string {
99+
func defaultKubeconfig() string {
95100
hd, err := os.UserHomeDir()
96-
if err != nil && !viper.IsSet("kubeconfig") {
97-
log.Fatal("Cannot determine homedir, pass in a kubeconfig location explicitly with --kubeconfig")
101+
if err != nil {
102+
return ""
98103
}
99-
return hd
104+
return filepath.Join(hd, ".kube", "config")
100105
}
101106

102107
func generateDomainEntries() {
@@ -147,11 +152,22 @@ func watchForExternalIP(ch <-chan watch.Event, outCh chan<- svcInfo) error {
147152
log.WithField("ing[0].Hostname", ing[0].Hostname).
148153
Debug("Using Hostname")
149154

150-
ip, _ := net.LookupIP(ing[0].Hostname)
155+
ips, err := lookupIP(ing[0].Hostname)
156+
if err != nil {
157+
log.WithError(err).
158+
WithField("hostname", ing[0].Hostname).
159+
Warn("Failed to resolve hostname")
160+
continue
161+
}
162+
if len(ips) == 0 {
163+
log.WithField("hostname", ing[0].Hostname).
164+
Warn("Hostname did not resolve to any IPs")
165+
continue
166+
}
151167

152168
outCh <- svcInfo{
153169
SvcName: svc.ObjectMeta.Name,
154-
Addr: ip[0].String(),
170+
Addr: ips[0].String(),
155171
}
156172
}
157173
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2018- The Pixie Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
*/
18+
19+
package main
20+
21+
import (
22+
"errors"
23+
"net"
24+
"testing"
25+
26+
v1 "k8s.io/api/core/v1"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
"k8s.io/apimachinery/pkg/watch"
29+
)
30+
31+
func TestWatchForExternalIPUsesResolvedHostname(t *testing.T) {
32+
restoreDNSState := setTestDNSState()
33+
defer restoreDNSState()
34+
35+
oldLookupIP := lookupIP
36+
lookupIP = func(host string) ([]net.IP, error) {
37+
if host != "example.com" {
38+
t.Fatalf("unexpected hostname: %s", host)
39+
}
40+
return []net.IP{net.ParseIP("203.0.113.10")}, nil
41+
}
42+
defer func() { lookupIP = oldLookupIP }()
43+
44+
events := make(chan watch.Event, 1)
45+
out := make(chan svcInfo, 1)
46+
events <- serviceEvent("cloud-proxy-service", "", "example.com")
47+
close(events)
48+
49+
if err := watchForExternalIP(events, out); err != nil {
50+
t.Fatalf("watchForExternalIP returned error: %v", err)
51+
}
52+
53+
got := <-out
54+
if got.SvcName != "cloud-proxy-service" {
55+
t.Fatalf("unexpected service name: %s", got.SvcName)
56+
}
57+
if got.Addr != "203.0.113.10" {
58+
t.Fatalf("unexpected address: %s", got.Addr)
59+
}
60+
}
61+
62+
func TestWatchForExternalIPSkipsUnresolvedHostname(t *testing.T) {
63+
restoreDNSState := setTestDNSState()
64+
defer restoreDNSState()
65+
66+
oldLookupIP := lookupIP
67+
lookupIP = func(host string) ([]net.IP, error) {
68+
return nil, errors.New("lookup failed")
69+
}
70+
defer func() { lookupIP = oldLookupIP }()
71+
72+
events := make(chan watch.Event, 1)
73+
out := make(chan svcInfo, 1)
74+
events <- serviceEvent("cloud-proxy-service", "", "example.com")
75+
close(events)
76+
77+
if err := watchForExternalIP(events, out); err != nil {
78+
t.Fatalf("watchForExternalIP returned error: %v", err)
79+
}
80+
81+
if len(out) != 0 {
82+
t.Fatalf("expected no service updates, got %d", len(out))
83+
}
84+
}
85+
86+
func setTestDNSState() func() {
87+
oldDNSEntries := dnsEntriesByService
88+
dnsEntriesByService = map[string][]string{
89+
"cloud-proxy-service": {"dev.withpixie.dev"},
90+
}
91+
return func() {
92+
dnsEntriesByService = oldDNSEntries
93+
}
94+
}
95+
96+
func serviceEvent(name string, ip string, hostname string) watch.Event {
97+
return watch.Event{
98+
Object: &v1.Service{
99+
ObjectMeta: metav1.ObjectMeta{
100+
Name: name,
101+
},
102+
Status: v1.ServiceStatus{
103+
LoadBalancer: v1.LoadBalancerStatus{
104+
Ingress: []v1.LoadBalancerIngress{
105+
{
106+
IP: ip,
107+
Hostname: hostname,
108+
},
109+
},
110+
},
111+
},
112+
},
113+
}
114+
}

0 commit comments

Comments
 (0)