This repository has been archived by the owner on May 11, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
forward.go
129 lines (117 loc) Β· 3.35 KB
/
forward.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package forward
import (
"fmt"
"net/url"
"regexp"
"strconv"
"strings"
"github.com/kamilsk/lift/internal/config"
"github.com/kamilsk/lift/internal/shell"
)
var (
port = regexp.MustCompile(`^\d+$`)
host = regexp.MustCompile(`^(?:\w+.?)+:(\d+)$`)
)
// Command returns a command to run the forward tool for a service.
func Command(cnf config.Service, detach bool) (shell.Command, error) {
var command shell.Command
args := make([]string, 0, 8)
for _, dep := range cnf.Dependencies {
if len(dep.Forward) == 0 {
continue
}
args = append(args, PodName(cnf.Name, dep.Name, true))
ports := make(map[uint16]struct{})
for _, env := range dep.Forward {
remote, err := ExtractPort(cnf.Environment[env])
if err != nil {
return command, err
}
if _, found := ports[remote]; found {
continue
}
ports[remote] = struct{}{}
forward := strconv.Itoa(int(remote))
if local, found := cnf.PortMapping[remote]; found {
forward = fmt.Sprintf("%d:%d", local, remote)
}
args = append(args, forward)
}
}
if len(args) > 0 {
if detach {
return shell.Command(fmt.Sprintf("forward -- %s &", strings.Join(args, " "))), nil
}
return shell.Command(fmt.Sprintf("forward -- %s", strings.Join(args, " "))), nil
}
return command, nil
}
// ExtractPort tries to extract a port number from a connection definition.
func ExtractPort(connection string) (uint16, error) {
switch {
case port.MatchString(connection):
p, err := strconv.ParseUint(connection, 10, 16)
return uint16(p), err
case host.MatchString(connection):
result := host.FindStringSubmatch(connection)
p, err := strconv.ParseUint(result[len(result)-1], 10, 16)
return uint16(p), err
default:
u, err := url.Parse(connection)
if err != nil {
return 0, err
}
p, err := strconv.ParseUint(u.Port(), 10, 16)
return uint16(p), nil
}
}
// PodName builds pod name.
func PodName(service, entity string, isLocal bool) string {
parts := append(make([]string, 0, 4), service)
if isLocal {
parts = append(parts, "local")
}
parts = append(parts, entity, "")
return strings.ToLower(strings.Join(parts, "-"))
}
// ReplacePort replaces a port number in a connection definition.
func ReplacePort(connection string, from, to uint16) string {
return strings.Replace(connection, strconv.FormatUint(uint64(from), 10), strconv.FormatUint(uint64(to), 10), 1)
}
// Shutdown returns commands to shutdown the forward tool.
func Shutdown(cnf config.Service) []shell.Command {
return []shell.Command{
"ps | grep '[f]orward --' | awk '{print $1}' | xargs kill -SIGKILL || true",
shell.Command(
fmt.Sprintf(
"ps | grep '[f]orward %s' | awk '{print $1}' | xargs kill -SIGKILL || true",
strings.TrimRight(PodName(cnf.Name, "", true), "-"),
),
),
}
}
// TransformEnvironment applies a port mapping to a copy of environment variables.
func TransformEnvironment(cnf config.Service) config.Environment {
if len(cnf.PortMapping) == 0 {
return cnf.Environment
}
copied := config.Environment{}
for k, v := range cnf.Environment {
copied[k] = v
}
for _, dep := range cnf.Dependencies {
if len(dep.Forward) == 0 {
continue
}
for _, env := range dep.Forward {
remote, err := ExtractPort(copied[env])
if err != nil {
continue
}
if local, found := cnf.PortMapping[remote]; found {
copied[env] = ReplacePort(copied[env], remote, local)
}
}
}
return copied
}