/
services.go
133 lines (113 loc) · 3.02 KB
/
services.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
130
131
132
133
package router
import (
"strconv"
"strings"
"github.com/nanobox-io/golang-portal-client"
"github.com/nanobox-io/nanobox-boxfile"
"github.com/nanobox-io/nanobox/models"
"github.com/nanobox-io/nanobox/util/display"
)
// Update the ports that portal knows about.
func BuildServices(appModel *models.App) []portal.Service {
services := []portal.Service{}
boxfile := loadBoxfile(appModel)
//
for _, node := range boxfile.Nodes("code") {
component, err := models.FindComponentBySlug(appModel.ID, node)
if err != nil {
continue // unable to get the component
}
//
for _, service := range buildComponentServices(boxfile.Node(node), component) {
if duplicateService(services, service) {
continue // if there is a duplicate port we will just contine
}
// add the new service to the list of services
services = append(services, service)
}
}
// send to portal
return services
}
// buildService builds all the tcp and udp port forwarding services
// it does not take into account any routing or information
func buildComponentServices(boxfile boxfile.Boxfile, component *models.Component) []portal.Service {
portServices := []portal.Service{}
//
for protocol, protocolMap := range ports(boxfile) {
for from, to := range protocolMap {
fromInt, _ := strconv.Atoi(from)
toInt, _ := strconv.Atoi(to)
portService := portal.Service{
Interface: "eth0",
Port: fromInt,
Type: protocol,
Scheduler: "rr",
Servers: []portal.Server{
{
Host: component.IPAddr(),
Port: toInt,
Forwarder: "m",
Weight: 1,
},
},
}
portServices = append(portServices, portService)
}
}
return portServices
}
// duplicateService ...
func duplicateService(services []portal.Service, service portal.Service) bool {
for _, existingService := range services {
if existingService.Port == service.Port {
return true
}
}
return false
}
// ports ...
func ports(box boxfile.Boxfile) map[string]map[string]string {
// we allow tcp and udp ports
rtn := map[string]map[string]string{
"tcp": {},
"udp": {},
}
// get the boxfiles ports section
ports, ok := box.Value("ports").([]interface{})
if !ok {
return rtn
}
// loop through the given ports and create hash data
// for each one.
for _, port := range ports {
p, ok := port.(string)
if ok {
portParts := strings.Split(p, ":")
switch len(portParts) {
case 1:
rtn["tcp"][portParts[0]] = portParts[0]
case 2:
rtn["tcp"][portParts[0]] = portParts[1]
case 3:
// the first part needs to be tcp or udp
// if it is neither we just assume tcp
switch portParts[0] {
case "udp":
rtn[portParts[0]][portParts[1]] = portParts[2]
case "tcp":
rtn["tcp"][portParts[1]] = portParts[2]
default:
display.BadPortType(portParts[0])
rtn["tcp"][portParts[1]] = portParts[2]
}
}
}
// if only a number is provided we assume tcp:num:num
portInt, ok := port.(int)
if ok {
rtn["tcp"][strconv.Itoa(portInt)] = strconv.Itoa(portInt)
}
}
return rtn
}