Skip to content

Commit 8966840

Browse files
authored
Merge pull request #13756 from ckannon/fixes/13746
ServiceCmd restructuring to repair docker/port-forward issues
2 parents e78c26f + 701b4be commit 8966840

File tree

5 files changed

+186
-131
lines changed

5 files changed

+186
-131
lines changed

cmd/minikube/cmd/service.go

+70-33
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"
@@ -102,10 +103,14 @@ var serviceCmd = &cobra.Command{
102103
services = newServices
103104
}
104105

106+
if services == nil || len(services) == 0 {
107+
exit.Message(reason.SvcNotFound, `Service '{{.service}}' was not found in '{{.namespace}}' namespace.
108+
You may select another namespace by using 'minikube service {{.service}} -n <namespace>'. Or list out all the services using 'minikube service list'`, out.V{"service": args[0], "namespace": namespace})
109+
}
110+
105111
var data [][]string
106-
var openUrls []string
107112
for _, svc := range services {
108-
openUrls, err := service.WaitForService(co.API, co.Config.Name, namespace, svc.Name, serviceURLTemplate, true, https, wait, interval)
113+
openUrls, err := service.WaitForService(co.API, co.Config.Name, namespace, svc.Name, serviceURLTemplate, serviceURLMode, https, wait, interval)
109114

110115
if err != nil {
111116
var s *service.SVCNotFoundError
@@ -128,35 +133,21 @@ You may select another namespace by using 'minikube service {{.service}} -n <nam
128133
}
129134

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

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]))
137+
if serviceURLMode && !driver.NeedsPortForward(co.Config.Driver) {
138+
out.String(fmt.Sprintf("%s\n", serviceURLs))
139+
}
139140
}
140141
}
141142

142-
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)
143+
if driver.NeedsPortForward(co.Config.Driver) && services != nil {
144+
startKicServiceTunnel(services, cname, co.Config.Driver)
145+
} else if !serviceURLMode {
146+
openURLs(data)
149147
}
150148
},
151149
}
152150

153-
func shouldOpen(args []string) bool {
154-
if !serviceURLMode && !all && len(args) == 1 {
155-
return true
156-
}
157-
return false
158-
}
159-
160151
func init() {
161152
serviceCmd.Flags().StringVarP(&namespace, "namespace", "n", "default", "The service namespace")
162153
serviceCmd.Flags().BoolVar(&serviceURLMode, "url", false, "Display the Kubernetes service URL in the CLI instead of opening it in the default browser")
@@ -168,7 +159,7 @@ func init() {
168159
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.")
169160
}
170161

171-
func startKicServiceTunnel(args []string, services service.URLs, configName, driverName string) {
162+
func startKicServiceTunnel(services service.URLs, configName, driverName string) {
172163
ctrlC := make(chan os.Signal, 1)
173164
signal.Notify(ctrlC, os.Interrupt)
174165

@@ -186,35 +177,81 @@ func startKicServiceTunnel(args []string, services service.URLs, configName, dri
186177
sshPort := strconv.Itoa(port)
187178
sshKey := filepath.Join(localpath.MiniPath(), "machines", configName, "id_rsa")
188179

189-
serviceTunnel := kic.NewServiceTunnel(sshPort, sshKey, clientset.CoreV1())
180+
serviceTunnel := kic.NewServiceTunnel(sshPort, sshKey, clientset.CoreV1(), serviceURLMode)
190181
urls, err := serviceTunnel.Start(svc.Name, namespace)
182+
191183
if err != nil {
192184
exit.Error(reason.SvcTunnelStart, "error starting tunnel", err)
193185
}
186+
// mutate response urls to HTTPS if needed
187+
urls, err = mutateURLs(svc.Name, urls)
188+
189+
if err != nil {
190+
exit.Error(reason.SvcTunnelStart, "error creatings urls", err)
191+
}
192+
194193
defer serviceTunnel.Stop()
194+
svc.URLs = urls
195195
data = append(data, []string{namespace, svc.Name, "", strings.Join(urls, "\n")})
196196
}
197197

198198
time.Sleep(1 * time.Second)
199199

200-
if !serviceURLMode && serviceURLFormat != defaultServiceFormatTemplate && !all {
200+
if !serviceURLMode {
201201
service.PrintServiceList(os.Stdout, data)
202+
} else {
203+
for _, row := range data {
204+
out.String(fmt.Sprintf("%s\n", row[3]))
205+
}
202206
}
203207

204-
if shouldOpen(args) {
205-
openURLs(services[0].Name, services[0].URLs)
208+
if !serviceURLMode {
209+
openURLs(data)
206210
}
207211

208212
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})
209213

210214
<-ctrlC
211215
}
212216

213-
func openURLs(svc string, urls []string) {
217+
func mutateURLs(serviceName string, urls []string) ([]string, error) {
218+
formattedUrls := make([]string, 0)
219+
for _, rawURL := range urls {
220+
var doc bytes.Buffer
221+
parsedURL, err := url.Parse(rawURL)
222+
if err != nil {
223+
exit.Error(reason.SvcTunnelStart, "No valid URL found for tunnel.", err)
224+
}
225+
port, err := strconv.Atoi(parsedURL.Port())
226+
if err != nil {
227+
exit.Error(reason.SvcTunnelStart, "No valid port found for tunnel.", err)
228+
}
229+
err = serviceURLTemplate.Execute(&doc, struct {
230+
IP string
231+
Port int32
232+
Name string
233+
}{
234+
parsedURL.Hostname(),
235+
int32(port),
236+
serviceName,
237+
})
238+
239+
if err != nil {
240+
return nil, err
241+
}
242+
243+
httpsURL, _ := service.OptionallyHTTPSFormattedURLString(doc.String(), https)
244+
formattedUrls = append(formattedUrls, httpsURL)
245+
}
246+
247+
return formattedUrls, nil
248+
}
249+
250+
func openURLs(urls [][]string) {
214251
for _, u := range urls {
215-
_, err := url.Parse(u)
252+
_, err := url.Parse(u[3])
216253
if err != nil {
217-
klog.Warningf("failed to parse url %q: %v (will not open)", u, err)
254+
klog.Warningf("failed to parse url %q: %v (will not open)", u[3], err)
218255
out.String(fmt.Sprintf("%s\n", u))
219256
continue
220257
}
@@ -224,8 +261,8 @@ func openURLs(svc string, urls []string) {
224261
continue
225262
}
226263

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 {
264+
out.Styled(style.Celebrate, "Opening service {{.namespace_name}}/{{.service_name}} in default browser...", out.V{"namespace_name": namespace, "service_name": u[1]})
265+
if err := browser.OpenURL(u[3]); err != nil {
229266
exit.Error(reason.HostBrowser, fmt.Sprintf("open url failed: %s", u), err)
230267
}
231268
}

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: suppressStdOut,
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
}

0 commit comments

Comments
 (0)