Skip to content

Commit 3cb27c6

Browse files
committed
✨ Support for using both an external control plane and automatic web hooks together.
This requires pre-filling LocalServingHost and possibly LocalServingExternalName with the right listen interface and external name so that the external control plane can reach the webhook server launched by envtest.
1 parent 33f1d80 commit 3cb27c6

File tree

8 files changed

+101
-20
lines changed

8 files changed

+101
-20
lines changed

pkg/builder/builder_suite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ var _ = BeforeSuite(func(done Done) {
6161
// Prevent the metrics listener being created
6262
metrics.DefaultBindAddress = "0"
6363

64-
webhook.DefaultPort, _, err = addr.Suggest()
64+
webhook.DefaultPort, _, err = addr.Suggest("")
6565
Expect(err).NotTo(HaveOccurred())
6666

6767
close(done)

pkg/envtest/webhook.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ type WebhookInstallOptions struct {
6767
// CAData is the CA that can be used to trust the serving certificates in LocalServingCertDir.
6868
LocalServingCAData []byte
6969

70+
// LocalServingHostExternalName is the hostname to use to reach the webhook server.
71+
LocalServingHostExternalName string
72+
7073
// MaxTime is the max time to wait
7174
MaxTime time.Duration
7275

@@ -137,13 +140,19 @@ func modifyWebhook(webhook map[string]interface{}, caData []byte, hostPort strin
137140
}
138141

139142
func (o *WebhookInstallOptions) generateHostPort() (string, error) {
140-
port, host, err := addr.Suggest()
141-
if err != nil {
142-
return "", fmt.Errorf("unable to grab random port for serving webhooks on: %v", err)
143+
if o.LocalServingPort == 0 {
144+
port, host, err := addr.Suggest(o.LocalServingHost)
145+
if err != nil {
146+
return "", fmt.Errorf("unable to grab random port for serving webhooks on: %v", err)
147+
}
148+
o.LocalServingPort = port
149+
o.LocalServingHost = host
150+
}
151+
host := o.LocalServingHostExternalName
152+
if host == "" {
153+
host = o.LocalServingHost
143154
}
144-
o.LocalServingPort = port
145-
o.LocalServingHost = host
146-
return net.JoinHostPort(host, fmt.Sprintf("%d", port)), nil
155+
return net.JoinHostPort(host, fmt.Sprintf("%d", o.LocalServingPort)), nil
147156
}
148157

149158
// PrepWithoutInstalling does the setup parts of Install (populating host-port,
@@ -266,7 +275,8 @@ func (o *WebhookInstallOptions) setupCA() ([]byte, error) {
266275
return nil, fmt.Errorf("unable to set up webhook CA: %v", err)
267276
}
268277

269-
hookCert, err := hookCA.NewServingCert()
278+
names := []string{"localhost", o.LocalServingHost, o.LocalServingHostExternalName}
279+
hookCert, err := hookCA.NewServingCert(names...)
270280
if err != nil {
271281
return nil, fmt.Errorf("unable to set up webhook serving certs: %v", err)
272282
}

pkg/internal/testing/integration/addr/manager.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ var cache = &portCache{
3838
ports: make(map[int]time.Time),
3939
}
4040

41-
func suggest() (port int, resolvedHost string, err error) {
42-
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
41+
func suggest(listenHost string) (port int, resolvedHost string, err error) {
42+
if listenHost == "" {
43+
listenHost = "localhost"
44+
}
45+
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(listenHost, "0"))
4346
if err != nil {
4447
return
4548
}
@@ -59,9 +62,9 @@ func suggest() (port int, resolvedHost string, err error) {
5962
// a tuple consisting of a free port and the hostname resolved to its IP.
6063
// It makes sure that new port allocated does not conflict with old ports
6164
// allocated within 1 minute.
62-
func Suggest() (port int, resolvedHost string, err error) {
65+
func Suggest(listenHost string) (port int, resolvedHost string, err error) {
6366
for i := 0; i < portConflictRetry; i++ {
64-
port, resolvedHost, err = suggest()
67+
port, resolvedHost, err = suggest(listenHost)
6568
if err != nil {
6669
return
6770
}

pkg/internal/testing/integration/addr/manager_test.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
var _ = Describe("SuggestAddress", func() {
1414
It("returns a free port and an address to bind to", func() {
15-
port, host, err := addr.Suggest()
15+
port, host, err := addr.Suggest("")
1616

1717
Expect(err).NotTo(HaveOccurred())
1818
Expect(host).To(Or(Equal("127.0.0.1"), Equal("::1")))
@@ -26,4 +26,36 @@ var _ = Describe("SuggestAddress", func() {
2626
}()
2727
Expect(err).NotTo(HaveOccurred())
2828
})
29+
30+
It("supports an explicit listenHost", func() {
31+
port, host, err := addr.Suggest("localhost")
32+
33+
Expect(err).NotTo(HaveOccurred())
34+
Expect(host).To(Or(Equal("127.0.0.1"), Equal("::1")))
35+
Expect(port).NotTo(Equal(0))
36+
37+
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
38+
Expect(err).NotTo(HaveOccurred())
39+
l, err := net.ListenTCP("tcp", addr)
40+
defer func() {
41+
Expect(l.Close()).To(Succeed())
42+
}()
43+
Expect(err).NotTo(HaveOccurred())
44+
})
45+
46+
It("supports a 0.0.0.0 listenHost", func() {
47+
port, host, err := addr.Suggest("0.0.0.0")
48+
49+
Expect(err).NotTo(HaveOccurred())
50+
Expect(host).To(Equal("0.0.0.0"))
51+
Expect(port).NotTo(Equal(0))
52+
53+
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
54+
Expect(err).NotTo(HaveOccurred())
55+
l, err := net.ListenTCP("tcp", addr)
56+
defer func() {
57+
Expect(l.Close()).To(Succeed())
58+
}()
59+
Expect(err).NotTo(HaveOccurred())
60+
})
2961
})

pkg/internal/testing/integration/apiserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func (s *APIServer) setProcessState() error {
105105

106106
// Defaulting the secure port
107107
if s.SecurePort == 0 {
108-
s.SecurePort, _, err = addr.Suggest()
108+
s.SecurePort, _, err = addr.Suggest("")
109109
if err != nil {
110110
return err
111111
}

pkg/internal/testing/integration/internal/process.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func DoDefaulting(
7575
}
7676

7777
if listenURL == nil {
78-
port, host, err := addr.Suggest()
78+
port, host, err := addr.Suggest("")
7979
if err != nil {
8080
return DefaultedProcessInput{}, err
8181
}

pkg/internal/testing/integration/internal/process_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ var _ = Describe("Start method", func() {
9797
processState.HealthCheckEndpoint = healthURLPath
9898
processState.StartTimeout = 500 * time.Millisecond
9999

100-
port, host, err := addr.Suggest()
100+
port, host, err := addr.Suggest("")
101101
Expect(err).NotTo(HaveOccurred())
102102

103103
processState.URL = url.URL{

pkg/internal/testing/integration/internal/tinyca.go

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,51 @@ func (c *TinyCA) makeCert(cfg certutil.Config) (CertPair, error) {
137137
}, nil
138138
}
139139

140-
// NewServingCert returns a new CertPair for a serving HTTPS on localhost.
141-
func (c *TinyCA) NewServingCert() (CertPair, error) {
140+
// NewServingCert returns a new CertPair for a serving HTTPS on localhost (or other specified names).
141+
func (c *TinyCA) NewServingCert(names ...string) (CertPair, error) {
142+
if len(names) == 0 {
143+
names = []string{"localhost"}
144+
}
145+
dnsNames, ips, err := resolveNames(names)
146+
if err != nil {
147+
return CertPair{}, err
148+
}
149+
142150
return c.makeCert(certutil.Config{
143151
CommonName: "localhost",
144152
Organization: []string{c.orgName},
145153
AltNames: certutil.AltNames{
146-
DNSNames: []string{"localhost"},
147-
IPs: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback},
154+
DNSNames: dnsNames,
155+
IPs: ips,
148156
},
149157
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
150158
})
151159
}
160+
161+
func resolveNames(names []string) ([]string, []net.IP, error) {
162+
dnsNames := []string{}
163+
ips := []net.IP{}
164+
for _, name := range names {
165+
if name == "" {
166+
continue
167+
}
168+
ip := net.ParseIP(name)
169+
if ip == nil {
170+
dnsNames = append(dnsNames, name)
171+
// Also resolve to IPs.
172+
nameIPs, err := net.LookupHost(name)
173+
if err != nil {
174+
return nil, nil, err
175+
}
176+
for _, nameIP := range nameIPs {
177+
ip = net.ParseIP(nameIP)
178+
if ip != nil {
179+
ips = append(ips, ip)
180+
}
181+
}
182+
} else {
183+
ips = append(ips, ip)
184+
}
185+
}
186+
return dnsNames, ips, nil
187+
}

0 commit comments

Comments
 (0)