-
Notifications
You must be signed in to change notification settings - Fork 74
/
Copy pathexternal_connectivity_test.go
221 lines (186 loc) · 6.74 KB
/
external_connectivity_test.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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
package acceptance_test
import (
"fmt"
"io"
"net/http"
"os"
"regexp"
"time"
"code.cloudfoundry.org/lib/testsupport"
"github.com/cloudfoundry/cf-test-helpers/v2/cf"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
)
var _ = Describe("external connectivity", func() {
var (
appA string
orgName string
spaceName string
appRoute string
)
BeforeEach(func() {
if testConfig.Internetless {
Skip("skipping external connectivity tests")
}
appA = fmt.Sprintf("appA-%d", randomGenerator.Int31())
orgName = testConfig.Prefix + "external-connectivity-org"
spaceName = testConfig.Prefix + "space"
setupOrgAndSpace(orgName, spaceName)
By("unbinding all running ASGs")
for _, sg := range testConfig.DefaultSecurityGroups {
Expect(cf.Cf("unbind-running-security-group", sg).Wait(Timeout_Short)).To(gexec.Exit(0))
}
By("creating test-generated ASGs")
for asgName, asgValue := range testASGs {
createASG(asgName, asgValue)
}
By("pushing the test app")
pushProxy(appA)
appRoute = fmt.Sprintf("http://%s.%s/", appA, config.AppsDomain)
})
AfterEach(func() {
By("adding back all the original running ASGs")
for _, sg := range testConfig.DefaultSecurityGroups {
Expect(cf.Cf("bind-running-security-group", sg).Wait(Timeout_Short)).To(gexec.Exit(0))
}
By("deleting the test org")
Expect(cf.Cf("delete-org", orgName, "-f").Wait(Timeout_Push)).To(gexec.Exit(0))
By("removing test-generated ASGs")
for asgName := range testASGs {
removeASG(asgName)
}
})
checkRequest := func(route string, expectedStatusCode int, expectedResponseRegex string) error {
regex := regexp.MustCompile(expectedResponseRegex)
resp, err := http.Get(route)
if err != nil {
return err
}
defer resp.Body.Close()
respBytes, err := io.ReadAll(resp.Body)
Expect(err).NotTo(HaveOccurred())
respBody := string(respBytes)
if resp.StatusCode != expectedStatusCode {
return fmt.Errorf("test http get to %s: expected response code %d but got %d. response body:\n%s", route, expectedStatusCode, resp.StatusCode, respBody)
}
if !regex.MatchString(respBody) {
return fmt.Errorf("test http get to %s: expected response to contain %q but instead saw:\n%s", route, expectedResponseRegex, respBody)
}
return nil
}
isReachable := func() error {
return checkRequest(appRoute, 200, `{"ListenAddresses":\[`)
}
canProxy := func() error {
return checkRequest(appRoute+"proxy/docs.cloudfoundry.org", 200, `https://docs\.cloudfoundry\.org`)
}
cannotProxy := func() error {
return checkRequest(appRoute+"proxy/docs.cloudfoundry.org", 500, "connection refused|i/o timeout")
}
canPing := func() error {
return checkRequest(appRoute+"ping/8.8.8.8", 200, "Ping succeeded")
}
cannotPing := func() error {
return checkRequest(appRoute+"ping/8.8.8.8", 500, `Ping failed to destination: 8\.8\.8\.8`)
}
Describe("basic (legacy) network behavior for an app", func() {
It("makes the app reachable from the router, and the app can reach the internet only if allowed", func(ctx SpecContext) {
By("checking that the app is reachable via the router")
Eventually(isReachable, "10s", "1s").Should(Succeed())
Consistently(isReachable, "2s", "0.5s").Should(Succeed())
By("checking that the app cannot reach the internet using http and dns")
Eventually(cannotProxy, "10s", "1s").Should(Succeed())
Consistently(cannotProxy, "2s", "0.5s").Should(Succeed())
By("checking that the app cannot ping the internet (first time)")
Consistently(cannotPing, "2s", "0.5s").Should(Succeed())
By("creating and binding a tcp and udp security group")
Expect(cfCLI.BindSecurityGroup("tcp-asg", orgName, spaceName)).To(Succeed())
Expect(cfCLI.BindSecurityGroup("udp-asg", orgName, spaceName)).To(Succeed())
if !testConfig.DynamicASGsEnabled {
By("if dynamic asgs are not enabled, restarting the app is required")
Expect(cf.Cf("restart", appA).Wait(Timeout_Push)).To(gexec.Exit(0))
}
By("checking that the app can use dns and http to reach the internet")
Eventually(canProxy, "180s", "1s").Should(Succeed())
Consistently(canProxy, "2s", "0.5s").Should(Succeed())
By("checking that the app cannot ping the internet (second time)")
Consistently(cannotPing, "2s", "1s").Should(Succeed())
By("removing the tcp security groups")
Expect(cfCLI.UnbindSecurityGroup("tcp-asg", orgName, spaceName)).To(Succeed())
if !testConfig.DynamicASGsEnabled {
By("restarting the app")
Expect(cf.Cf("restart", appA).Wait(Timeout_Push)).To(gexec.Exit(0))
} else {
time.Sleep(90 * time.Second)
}
By("checking that the app cannot use http to reach the internet")
Consistently(cannotProxy, "180s", "0.5s").Should(Succeed())
}, SpecTimeout(10*time.Minute))
It("allows outbound ICMP only if allowed", func(ctx SpecContext) {
if testConfig.SkipICMPTests {
Skip("Test config has 'skip_icmp_test: true', skipping ICMP connectivity tests")
}
By("checking that the app cannot ping the internet")
Consistently(cannotPing, "2s", "0.5s").Should(Succeed())
By("creating and binding an icmp security group")
Expect(cfCLI.BindSecurityGroup("icmp-asg", orgName, spaceName)).To(Succeed())
if !testConfig.DynamicASGsEnabled {
By("restarting the app")
Expect(cf.Cf("restart", appA).Wait(Timeout_Push)).To(gexec.Exit(0))
}
By("checking that the app can ping the internet")
Eventually(canPing, "180s", "1s").Should(Succeed())
Consistently(canPing, "2s", "0.5s").Should(Succeed())
}, SpecTimeout(
(2*Timeout_Push)+ // Two 'cf pushes' occur in this test
(180*time.Second)+ // One 180s 'Eventually'
(2*2*time.Second), // Two 2s 'Consistently'
))
})
})
func createASG(name string, asgDefinition string) {
asgFile, err := testsupport.CreateTempFile(asgDefinition)
Expect(err).NotTo(HaveOccurred())
Expect(cfCLI.CreateSecurityGroup(name, asgFile)).To(Succeed())
Expect(os.Remove(asgFile)).To(Succeed())
}
func removeASG(name string) {
Expect(cfCLI.DeleteSecurityGroup(name)).To(Succeed())
}
func setupOrgAndSpace(orgName, spaceName string) {
Expect(cf.Cf("create-org", orgName).Wait(Timeout_Push)).To(gexec.Exit(0))
Expect(cf.Cf("target", "-o", orgName).Wait(Timeout_Push)).To(gexec.Exit(0))
Expect(cf.Cf("create-space", spaceName, "-o", orgName).Wait(Timeout_Push)).To(gexec.Exit(0))
Expect(cf.Cf("target", "-o", orgName, "-s", spaceName).Wait(Timeout_Push)).To(gexec.Exit(0))
}
var testASGs = map[string]string{
"tcp-asg": `
[
{
"destination": "0.0.0.0-255.255.255.255",
"protocol": "tcp",
"ports": "80,443"
}
]
`,
"udp-asg": `
[
{
"destination": "0.0.0.0-255.255.255.255",
"protocol": "udp",
"ports": "53"
}
]
`,
"icmp-asg": `
[
{
"destination": "0.0.0.0-255.255.255.255",
"protocol": "icmp",
"type": 8,
"code": 0
}
]
`,
}