Skip to content

Commit 83aad39

Browse files
committed
Fix flow to support docker driver properly for mac, issue #13736
1 parent 362d5fd commit 83aad39

File tree

5 files changed

+109
-129
lines changed

5 files changed

+109
-129
lines changed

cmd/minikube/cmd/service.go

+55-32
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package cmd
1818

1919
import (
20+
"bytes"
2021
"errors"
2122
"fmt"
2223
"net/url"
@@ -103,9 +104,8 @@ var serviceCmd = &cobra.Command{
103104
}
104105

105106
var data [][]string
106-
var openUrls []string
107107
for _, svc := range services {
108-
openUrls, err := service.WaitForService(co.API, co.Config.Name, namespace, svc.Name, serviceURLTemplate, true, https, wait, interval)
108+
openUrls, err := service.WaitForService(co.API, co.Config.Name, namespace, svc.Name, serviceURLTemplate, serviceURLMode, https, wait, interval)
109109

110110
if err != nil {
111111
var s *service.SVCNotFoundError
@@ -128,35 +128,21 @@ You may select another namespace by using 'minikube service {{.service}} -n <nam
128128
}
129129

130130
data = append(data, []string{svc.Namespace, svc.Name, servicePortNames, serviceURLs})
131-
}
132-
}
133131

134-
if (!serviceURLMode && serviceURLFormat != defaultServiceFormatTemplate && !all) || all {
135-
service.PrintServiceList(os.Stdout, data)
136-
} else if serviceURLMode && !all {
137-
for _, u := range data {
138-
out.String(fmt.Sprintf("%s\n", u[3]))
132+
if serviceURLMode && !driver.NeedsPortForward(co.Config.Driver) {
133+
out.String(fmt.Sprintf("%s\n", serviceURLs))
134+
}
139135
}
140136
}
141137

142138
if driver.NeedsPortForward(co.Config.Driver) {
143-
startKicServiceTunnel(args, services, cname, co.Config.Driver)
144-
return
145-
}
146-
147-
if !serviceURLMode && !all && len(args) == 1 {
148-
openURLs(args[0], openUrls)
139+
startKicServiceTunnel(services, cname, co.Config.Driver)
140+
} else if !serviceURLMode {
141+
openURLs(data)
149142
}
150143
},
151144
}
152145

153-
func shouldOpen(args []string) bool {
154-
if !serviceURLMode && !all && len(args) == 1 {
155-
return true
156-
}
157-
return false
158-
}
159-
160146
func init() {
161147
serviceCmd.Flags().StringVarP(&namespace, "namespace", "n", "default", "The service namespace")
162148
serviceCmd.Flags().BoolVar(&serviceURLMode, "url", false, "Display the Kubernetes service URL in the CLI instead of opening it in the default browser")
@@ -168,7 +154,7 @@ func init() {
168154
serviceCmd.PersistentFlags().StringVar(&serviceURLFormat, "format", defaultServiceFormatTemplate, "Format to output service URL in. This format will be applied to each url individually and they will be printed one at a time.")
169155
}
170156

171-
func startKicServiceTunnel(args []string, services service.URLs, configName, driverName string) {
157+
func startKicServiceTunnel(services service.URLs, configName, driverName string) {
172158
ctrlC := make(chan os.Signal, 1)
173159
signal.Notify(ctrlC, os.Interrupt)
174160

@@ -186,35 +172,72 @@ func startKicServiceTunnel(args []string, services service.URLs, configName, dri
186172
sshPort := strconv.Itoa(port)
187173
sshKey := filepath.Join(localpath.MiniPath(), "machines", configName, "id_rsa")
188174

189-
serviceTunnel := kic.NewServiceTunnel(sshPort, sshKey, clientset.CoreV1())
175+
serviceTunnel := kic.NewServiceTunnel(sshPort, sshKey, clientset.CoreV1(), serviceURLMode)
190176
urls, err := serviceTunnel.Start(svc.Name, namespace)
177+
178+
//mutate response urls to HTTPS if needed
179+
urls = mutateURLs(svc.Name, urls)
180+
191181
if err != nil {
192182
exit.Error(reason.SvcTunnelStart, "error starting tunnel", err)
193183
}
194184
defer serviceTunnel.Stop()
185+
svc.URLs = urls
195186
data = append(data, []string{namespace, svc.Name, "", strings.Join(urls, "\n")})
196187
}
197188

198189
time.Sleep(1 * time.Second)
199190

200-
if !serviceURLMode && serviceURLFormat != defaultServiceFormatTemplate && !all {
191+
if !serviceURLMode {
201192
service.PrintServiceList(os.Stdout, data)
193+
} else {
194+
for _, row := range data {
195+
out.String(fmt.Sprintf("%s\n", row[3]))
196+
}
202197
}
203198

204-
if shouldOpen(args) {
205-
openURLs(services[0].Name, services[0].URLs)
199+
if !serviceURLMode {
200+
openURLs(data)
206201
}
207202

208203
out.WarningT("Because you are using a Docker driver on {{.operating_system}}, the terminal needs to be open to run it.", out.V{"operating_system": runtime.GOOS})
209204

210205
<-ctrlC
211206
}
212207

213-
func openURLs(svc string, urls []string) {
208+
func mutateURLs(serviceName string, urls []string) []string {
209+
formattedUrls := make([]string, 0)
210+
for _, rawUrl := range urls {
211+
var doc bytes.Buffer
212+
parsedUrl, err := url.Parse(rawUrl)
213+
if err != nil {
214+
exit.Error(reason.SvcTunnelStart, "No valid URL found for tunnel.", err)
215+
}
216+
port, err := strconv.Atoi(parsedUrl.Port())
217+
if err != nil {
218+
exit.Error(reason.SvcTunnelStart, "No valid port found for tunnel.", err)
219+
}
220+
err = serviceURLTemplate.Execute(&doc, struct {
221+
IP string
222+
Port int32
223+
Name string
224+
}{
225+
parsedUrl.Hostname(),
226+
int32(port),
227+
serviceName,
228+
})
229+
httpsUrl, _ := service.OptionallyHTTPSFormattedURLString(doc.String(), https)
230+
formattedUrls = append(formattedUrls, httpsUrl)
231+
}
232+
233+
return formattedUrls
234+
}
235+
236+
func openURLs(urls [][]string) {
214237
for _, u := range urls {
215-
_, err := url.Parse(u)
238+
_, err := url.Parse(u[3])
216239
if err != nil {
217-
klog.Warningf("failed to parse url %q: %v (will not open)", u, err)
240+
klog.Warningf("failed to parse url %q: %v (will not open)", u[3], err)
218241
out.String(fmt.Sprintf("%s\n", u))
219242
continue
220243
}
@@ -224,8 +247,8 @@ func openURLs(svc string, urls []string) {
224247
continue
225248
}
226249

227-
out.Styled(style.Celebrate, "Opening service {{.namespace_name}}/{{.service_name}} in default browser...", out.V{"namespace_name": namespace, "service_name": svc})
228-
if err := browser.OpenURL(u); err != nil {
250+
out.Styled(style.Celebrate, "Opening service {{.namespace_name}}/{{.service_name}} in default browser...", out.V{"namespace_name": namespace, "service_name": u[1]})
251+
if err := browser.OpenURL(u[3]); err != nil {
229252
exit.Error(reason.HostBrowser, fmt.Sprintf("open url failed: %s", u), err)
230253
}
231254
}

cmd/minikube/cmd/service_test.go

-71
This file was deleted.

pkg/minikube/tunnel/kic/service_tunnel.go

+11-8
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,20 @@ import (
3030

3131
// ServiceTunnel ...
3232
type ServiceTunnel struct {
33-
sshPort string
34-
sshKey string
35-
v1Core typed_core.CoreV1Interface
36-
sshConn *sshConn
33+
sshPort string
34+
sshKey string
35+
v1Core typed_core.CoreV1Interface
36+
sshConn *sshConn
37+
suppressStdOut bool
3738
}
3839

3940
// NewServiceTunnel ...
40-
func NewServiceTunnel(sshPort, sshKey string, v1Core typed_core.CoreV1Interface) *ServiceTunnel {
41+
func NewServiceTunnel(sshPort, sshKey string, v1Core typed_core.CoreV1Interface, suppressStdOut bool) *ServiceTunnel {
4142
return &ServiceTunnel{
42-
sshPort: sshPort,
43-
sshKey: sshKey,
44-
v1Core: v1Core,
43+
sshPort: sshPort,
44+
sshKey: sshKey,
45+
v1Core: v1Core,
46+
suppressStdOut: false,
4547
}
4648
}
4749

@@ -58,6 +60,7 @@ func (t *ServiceTunnel) Start(svcName, namespace string) ([]string, error) {
5860
}
5961

6062
go func() {
63+
t.sshConn.suppressStdOut = t.suppressStdOut
6164
err = t.sshConn.startAndWait()
6265
if err != nil {
6366
klog.Errorf("error starting ssh tunnel: %v", err)

pkg/minikube/tunnel/kic/ssh_conn.go

+15-8
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ import (
3030
)
3131

3232
type sshConn struct {
33-
name string
34-
service string
35-
cmd *exec.Cmd
36-
ports []int
37-
activeConn bool
33+
name string
34+
service string
35+
cmd *exec.Cmd
36+
ports []int
37+
activeConn bool
38+
suppressStdOut bool
3839
}
3940

4041
func createSSHConn(name, sshPort, sshKey string, resourcePorts []int32, resourceIP string, resourceName string) *sshConn {
@@ -139,7 +140,9 @@ func createSSHConnWithRandomPorts(name, sshPort, sshKey string, svc *v1.Service)
139140
}
140141

141142
func (c *sshConn) startAndWait() error {
142-
out.Step(style.Running, "Starting tunnel for service {{.service}}.", out.V{"service": c.service})
143+
if !c.suppressStdOut {
144+
out.Step(style.Running, "Starting tunnel for service {{.service}}.", out.V{"service": c.service})
145+
}
143146

144147
err := c.cmd.Start()
145148
if err != nil {
@@ -159,14 +162,18 @@ func (c *sshConn) startAndWait() error {
159162
func (c *sshConn) stop() error {
160163
if c.activeConn {
161164
c.activeConn = false
162-
out.Step(style.Stopping, "Stopping tunnel for service {{.service}}.", out.V{"service": c.service})
165+
if !c.suppressStdOut {
166+
out.Step(style.Stopping, "Stopping tunnel for service {{.service}}.", out.V{"service": c.service})
167+
}
163168
err := c.cmd.Process.Kill()
164169
if err == os.ErrProcessDone {
165170
// No need to return an error here
166171
return nil
167172
}
168173
return err
169174
}
170-
out.Step(style.Stopping, "Stopped tunnel for service {{.service}}.", out.V{"service": c.service})
175+
if !c.suppressStdOut {
176+
out.Step(style.Stopping, "Stopped tunnel for service {{.service}}.", out.V{"service": c.service})
177+
}
171178
return nil
172179
}

test/integration/functional_test.go

+28-10
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,11 @@ func validateProfileCmd(ctx context.Context, t *testing.T, profile string) {
13991399
})
14001400
}
14011401

1402+
func killContext(cmdContext *exec.Cmd, killDelay time.Duration) {
1403+
time.Sleep(killDelay)
1404+
cmdContext.Process.Signal(os.Interrupt)
1405+
}
1406+
14021407
// validateServiceCmd asserts basic "service" command functionality
14031408
func validateServiceCmd(ctx context.Context, t *testing.T, profile string) {
14041409
defer PostMortemLogs(t, profile)
@@ -1460,18 +1465,18 @@ func validateServiceCmd(ctx context.Context, t *testing.T, profile string) {
14601465
t.Errorf("expected 'service list' to contain *hello-node* but got -%q-", rr.Stdout.String())
14611466
}
14621467

1468+
t.Logf("Needs port forward: %t, %s", NeedsPortForward(), runtime.GOOS)
1469+
1470+
// docs: Run `minikube service` with `--https --url` to make sure the HTTPS endpoint URL of the service is printed
1471+
cmdContext := exec.CommandContext(ctx, Target(), "-p", profile, "service", "--namespace=default", "--https", "--url", "hello-node")
14631472
if NeedsPortForward() {
1464-
t.Skipf("test is broken for port-forwarded drivers: https://github.com/kubernetes/minikube/issues/7383")
1473+
go killContext(cmdContext, 2*time.Second)
14651474
}
14661475

1467-
// docs: Run `minikube service` with `--https --url` to make sure the HTTPS endpoint URL of the service is printed
1468-
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "service", "--namespace=default", "--https", "--url", "hello-node"))
1469-
if err != nil {
1476+
rr, err = Run(t, cmdContext)
1477+
if err != nil && !strings.Contains(err.Error(), "interrupt") {
14701478
t.Fatalf("failed to get service url. args %q : %v", rr.Command(), err)
14711479
}
1472-
if rr.Stderr.String() != "" {
1473-
t.Errorf("expected stderr to be empty but got *%q* . args %q", rr.Stderr, rr.Command())
1474-
}
14751480

14761481
splits := strings.Split(rr.Stdout.String(), "|")
14771482
var endpoint string
@@ -1491,17 +1496,26 @@ func validateServiceCmd(ctx context.Context, t *testing.T, profile string) {
14911496
t.Errorf("expected scheme for %s to be 'https' but got %q", endpoint, u.Scheme)
14921497
}
14931498

1499+
cmdContext = exec.CommandContext(ctx, Target(), "-p", profile, "service", "hello-node", "--url", "--format={{.IP}}")
1500+
if NeedsPortForward() {
1501+
go killContext(cmdContext, 2*time.Second)
1502+
}
14941503
// docs: Run `minikube service` with `--url --format={{.IP}}` to make sure the IP address of the service is printed
1495-
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "service", "hello-node", "--url", "--format={{.IP}}"))
1496-
if err != nil {
1504+
rr, err = Run(t, cmdContext)
1505+
if err != nil && !strings.Contains(err.Error(), "interrupt") {
14971506
t.Errorf("failed to get service url with custom format. args %q: %v", rr.Command(), err)
14981507
}
1508+
14991509
if strings.TrimSpace(rr.Stdout.String()) != u.Hostname() {
15001510
t.Errorf("expected 'service --format={{.IP}}' output to be -%q- but got *%q* . args %q.", u.Hostname(), rr.Stdout.String(), rr.Command())
15011511
}
15021512

1513+
cmdContext = exec.CommandContext(ctx, Target(), "-p", profile, "service", "hello-node", "--url")
1514+
if NeedsPortForward() {
1515+
go killContext(cmdContext, 2*time.Second)
1516+
}
15031517
// docs: Run `minikube service` with a regular `--url` to make sure the HTTP endpoint URL of the service is printed
1504-
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "service", "hello-node", "--url"))
1518+
rr, err = Run(t, cmdContext)
15051519
if err != nil {
15061520
t.Errorf("failed to get service url. args: %q: %v", rr.Command(), err)
15071521
}
@@ -1518,6 +1532,10 @@ func validateServiceCmd(ctx context.Context, t *testing.T, profile string) {
15181532
t.Fatalf("expected scheme to be -%q- got scheme: *%q*", "http", u.Scheme)
15191533
}
15201534

1535+
if NeedsPortForward() {
1536+
t.Skipf("test is broken for port-forwarded drivers: https://github.com/kubernetes/minikube/issues/7383")
1537+
}
1538+
15211539
t.Logf("Attempting to fetch %s ...", endpoint)
15221540

15231541
// docs: Make sure we can hit the endpoint URL with an HTTP GET request

0 commit comments

Comments
 (0)