...
1 package kubeportforward
2
3 import (
4 "errors"
5 "fmt"
6 "io"
7 "regexp"
8 "strconv"
9 "strings"
10
11 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
12 "github.com/fatih/color"
13
14 "github.com/redhat-developer/odo/pkg/api"
15 "github.com/redhat-developer/odo/pkg/libdevfile"
16 "github.com/redhat-developer/odo/pkg/log"
17
18 "k8s.io/klog"
19 )
20
21 type PortWriter struct {
22 buffer io.Writer
23 end chan bool
24 len int
25
26 mapping map[string][]v1alpha2.Endpoint
27 fwPorts []api.ForwardedPort
28 customAddress string
29 }
30
31
32
33 func NewPortWriter(buffer io.Writer, len int, mapping map[string][]v1alpha2.Endpoint, customAddress string) *PortWriter {
34 return &PortWriter{
35 buffer: buffer,
36 len: len,
37 end: make(chan bool),
38 mapping: mapping,
39 customAddress: customAddress,
40 }
41 }
42
43 func (o *PortWriter) Write(buf []byte) (n int, err error) {
44
45 if o.customAddress == "" {
46 o.customAddress = "127.0.0.1"
47 }
48 s := string(buf)
49 if strings.HasPrefix(s, fmt.Sprintf("Forwarding from %s", o.customAddress)) {
50
51 fwPort, err := getForwardedPort(o.mapping, s, o.customAddress)
52 if err == nil {
53 o.fwPorts = append(o.fwPorts, fwPort)
54 } else {
55 klog.V(4).Infof("unable to get forwarded port: %v", err)
56 }
57
58
59 fmt.Fprintf(o.buffer, " - %s", log.SboldColor(color.FgGreen, s))
60 o.len--
61 if o.len == 0 {
62 o.end <- true
63 }
64 }
65 return len(buf), nil
66 }
67
68 func (o *PortWriter) Wait() {
69 <-o.end
70 }
71
72 func (o *PortWriter) GetForwardedPorts() []api.ForwardedPort {
73 return o.fwPorts
74 }
75
76 func getForwardedPort(mapping map[string][]v1alpha2.Endpoint, s string, address string) (api.ForwardedPort, error) {
77 if address == "" {
78 address = "127.0.0.1"
79 }
80 regex := regexp.MustCompile(fmt.Sprintf(`Forwarding from %s:([0-9]+) -> ([0-9]+)`, address))
81 matches := regex.FindStringSubmatch(s)
82 if len(matches) < 3 {
83 return api.ForwardedPort{}, errors.New("unable to analyze port forwarding string")
84 }
85 localPort, err := strconv.Atoi(matches[1])
86 if err != nil {
87 return api.ForwardedPort{}, err
88 }
89 remotePort, err := strconv.Atoi(matches[2])
90 if err != nil {
91 return api.ForwardedPort{}, err
92 }
93 fp := api.ForwardedPort{
94 LocalAddress: address,
95 LocalPort: localPort,
96 ContainerPort: remotePort,
97 }
98 containerLoop:
99 for container, endpoints := range mapping {
100 for _, ep := range endpoints {
101 if ep.TargetPort == remotePort {
102 fp.ContainerName = container
103 fp.PortName = ep.Name
104 fp.Exposure = string(ep.Exposure)
105 fp.IsDebug = libdevfile.IsDebugPort(ep.Name)
106 fp.Protocol = string(ep.Protocol)
107 break containerLoop
108 }
109 }
110 }
111 return fp, nil
112 }
113
View as plain text