This repository has been archived by the owner on Jan 5, 2023. It is now read-only.
/
ports.go
184 lines (157 loc) · 4.57 KB
/
ports.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package userconfig
import (
"encoding/json"
"fmt"
"sort"
"github.com/giantswarm/generic-types-go"
"github.com/juju/errgo"
)
type PortDefinitions []generictypes.DockerPort
type portDefinitions PortDefinitions
// Validate tries to validate the current PortDefinitions. If valCtx is nil,
// nothing can be validated. The given valCtx must provide at least one
// protocol, or Validate returns an error. The currently valid one should only
// be TCP.
func (pds PortDefinitions) Validate(valCtx *ValidationContext) error {
if valCtx == nil {
return nil
}
if len(valCtx.Protocols) == 0 {
return errgo.Newf("missing protocol in validation context")
}
for _, port := range pds {
if !contains(valCtx.Protocols, port.Protocol) {
return maskf(InvalidPortConfigError, "invalid protocol '%s' for port '%s', expected one of %v", port.Protocol, port.Port, valCtx.Protocols)
}
}
return nil
}
// UnmarshalJSON performs custom unmarshalling to support smart
// data types.
func (pds *PortDefinitions) UnmarshalJSON(data []byte) error {
if data[0] != '[' {
// Must be a single value, convert to an array of one
newData := []byte{}
newData = append(newData, '[')
newData = append(newData, data...)
newData = append(newData, ']')
data = newData
}
var local portDefinitions
if err := json.Unmarshal(data, &local); err != nil {
return mask(err)
}
*pds = PortDefinitions(local)
return nil
}
// String returns the marshalled and ordered string represantion of its own
// incarnation. It is important to have the string represantion ordered, since
// we use it to compare two PortDefinitions when creating a diff. See diff.go
func (pds *PortDefinitions) String() string {
list := []string{}
for _, pd := range *pds {
list = append(list, pd.String())
}
sort.Strings(list)
raw, err := json.Marshal(list)
if err != nil {
panic(fmt.Sprintf("%#v\n", mask(err)))
}
return string(raw)
}
func (pds PortDefinitions) contains(port generictypes.DockerPort) bool {
for _, pd := range pds {
// generictypes.DockerPort implements Equals to properly compare the
// format "<port>/<protocol>"
if pd.Equals(port) {
return true
}
}
return false
}
func contains(protocols []string, protocol string) bool {
for _, p := range protocols {
if p == protocol {
return true
}
}
return false
}
// validateUniqueDependenciesInPods checks that there are no dependencies with same alias and different port/name
func (nds *ComponentDefinitions) validateUniqueDependenciesInPods() error {
for componentName, componentDef := range *nds {
if !componentDef.IsPodRoot() {
continue
}
// Collect all dependencies in this pod
podComponents, err := nds.PodComponents(componentName)
if err != nil {
return mask(err)
}
list := LinkDefinitions{}
for _, pn := range podComponents {
if pn.Links == nil {
// No dependencies
continue
}
list = append(list, pn.Links...)
}
// Check list for duplicates
for i, l1 := range list {
alias1, err := l1.LinkName()
if err != nil {
return mask(err)
}
for j := i + 1; j < len(list); j++ {
l2 := list[j]
alias2, err := l2.LinkName()
if err != nil {
return mask(err)
}
if alias1 == alias2 {
// Same alias, Port must match and Name must match
if !l1.TargetPort.Equals(l2.TargetPort) {
return maskf(InvalidDependencyConfigError, "duplicate (with different ports) dependency '%s' in pod under '%s'", alias1, componentName.String())
}
if l1.Component != l2.Component {
return maskf(InvalidDependencyConfigError, "duplicate (with different names) dependency '%s' in pod under '%s'", alias1, componentName.String())
}
}
}
}
}
// No errors detected
return nil
}
// validateUniquePortsInPods checks that there are no duplicate ports in a single pod
func (nds *ComponentDefinitions) validateUniquePortsInPods() error {
for componentName, componentDef := range *nds {
if !componentDef.IsPodRoot() {
continue
}
// Collect all ports in this pod
podComponents, err := nds.PodComponents(componentName)
if err != nil {
return mask(err)
}
list := []generictypes.DockerPort{}
for _, pn := range podComponents {
if pn.Ports == nil {
// No dependencies
continue
}
list = append(list, pn.Ports...)
}
// Check list for duplicates
for i, port1 := range list {
for j := i + 1; j < len(list); j++ {
port2 := list[j]
if port1.Equals(port2) {
return maskf(InvalidPortConfigError, "multiple components export port '%s' in pod under '%s'", port1.String(), componentName.String())
}
}
}
}
// No errors detected
return nil
}