forked from openservicemesh/osm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathe2e_client_server_connectivity_test.go
249 lines (207 loc) · 8.85 KB
/
e2e_client_server_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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
package e2e
import (
"context"
"fmt"
"strings"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
"github.com/openservicemesh/osm/pkg/tests"
"github.com/openservicemesh/osm/pkg/constants"
. "github.com/openservicemesh/osm/tests/framework"
)
var _ = OSMDescribe("Test HTTP traffic from 1 pod client -> 1 pod server",
OSMDescribeInfo{
Tier: 1,
Bucket: 7,
OS: OSCrossPlatform,
},
func() {
Context("Test traffic flowing from client to server with a Kubernetes Service for the Source: HTTP", func() {
withSourceKubernetesService := true
testTraffic(withSourceKubernetesService, PodCommandDefault, false)
})
Context("Test traffic flowing from client to server without a Kubernetes Service for the Source: HTTP", func() {
// Prior iterations of OSM required that a source pod belong to a Kubernetes service
// for the Envoy proxy to be configured for outbound traffic to some remote server.
// This test ensures we test this scenario: client Pod is not associated w/ a service.
withSourceKubernetesService := false
testTraffic(withSourceKubernetesService, PodCommandDefault, false)
})
Context("Test traffic flowing from client to a server with a podIP bind", func() {
// Prior iterations of OSM didn't allow mesh services to bind to the podIP
// This test ensures that that behavior is configurable via MeshConfig
withSourceKubernetesService := true
testTraffic(withSourceKubernetesService, []string{"gunicorn", "-b", "$(POD_IP):80", "httpbin:app", "-k", "gevent"}, false, WithLocalProxyMode(v1alpha2.LocalProxyModePodIP))
})
Context("Test traffic flowing from client to a headless service without a Kubernetes Service for the Source: HTTP", func() {
// Prior iterations of OSM required that a source pod belong to a Kubernetes service
// for the Envoy proxy to be configured for outbound traffic to some remote server.
// This test ensures we test this scenario: client Pod is not associated w/ a service.
withSourceKubernetesService := true
testTraffic(withSourceKubernetesService, PodCommandDefault, true)
})
})
func testTraffic(withSourceKubernetesService bool, destPodCommand []string, destServiceHeadless bool, installOpts ...InstallOsmOpt) {
const sourceName = "client"
const destName = "server"
var ns = []string{sourceName, destName}
It("Tests HTTP traffic for client pod -> server pod", func() {
// Install OSM
Expect(Td.InstallOSM(Td.GetOSMInstallOpts(installOpts...))).To(Succeed())
// Create Test NS
for _, n := range ns {
Expect(Td.CreateNs(n, nil)).To(Succeed())
Expect(Td.AddNsToMesh(true, n)).To(Succeed())
}
// Get simple pod definitions for the HTTP server
svcAccDef, podDef, svcDef, err := Td.GetOSSpecificHTTPBinPod(destName, destName, destPodCommand...)
Expect(err).NotTo(HaveOccurred())
_, err = Td.CreateServiceAccount(destName, &svcAccDef)
Expect(err).NotTo(HaveOccurred())
_, err = Td.CreatePod(destName, podDef)
Expect(err).NotTo(HaveOccurred())
dstSvc, err := Td.CreateService(destName, *tests.HeadlessSvc(&svcDef))
Expect(err).NotTo(HaveOccurred())
// Expect it to be up and running in it's receiver namespace
Expect(Td.WaitForPodsRunningReady(destName, 90*time.Second, 1, nil)).To(Succeed())
srcPod := setupSource(sourceName, withSourceKubernetesService)
By("Creating SMI policies")
// Deploy allow rule client->server
httpRG, trafficTarget := Td.CreateSimpleAllowPolicy(
SimpleAllowPolicy{
RouteGroupName: "routes",
TrafficTargetName: "test-target",
SourceNamespace: sourceName,
SourceSVCAccountName: srcPod.Spec.ServiceAccountName,
DestinationNamespace: destName,
DestinationSvcAccountName: svcAccDef.Name,
})
// Configs have to be put into a monitored NS
_, err = Td.CreateHTTPRouteGroup(destName, httpRG)
Expect(err).NotTo(HaveOccurred())
_, err = Td.CreateTrafficTarget(destName, trafficTarget)
Expect(err).NotTo(HaveOccurred())
// All ready. Expect client to reach server
clientToServer := HTTPRequestDef{
SourceNs: sourceName,
SourcePod: srcPod.Name,
SourceContainer: sourceName,
Destination: fmt.Sprintf("%s.%s.svc.cluster.local", dstSvc.Name, dstSvc.Namespace),
}
srcToDestStr := fmt.Sprintf("%s -> %s",
fmt.Sprintf("%s/%s", sourceName, srcPod.Name),
clientToServer.Destination)
cond := Td.WaitForRepeatedSuccess(func() bool {
result := Td.HTTPRequest(clientToServer)
if result.Err != nil || result.StatusCode != 200 {
Td.T.Logf("> (%s) HTTP Req failed %d %v",
srcToDestStr, result.StatusCode, result.Err)
return false
}
Td.T.Logf("> (%s) HTTP Req succeeded: %d", srcToDestStr, result.StatusCode)
return true
}, 5, Td.ReqSuccessTimeout)
sourceService := map[bool]string{true: "with", false: "without"}[withSourceKubernetesService]
Expect(cond).To(BeTrue(), "Failed testing HTTP traffic from source pod %s Kubernetes Service to a destination", sourceService)
By("Deleting SMI policies")
Expect(Td.SmiClients.AccessClient.AccessV1alpha3().TrafficTargets(destName).Delete(context.TODO(), trafficTarget.Name, metav1.DeleteOptions{})).To(Succeed())
Expect(Td.SmiClients.SpecClient.SpecsV1alpha4().HTTPRouteGroups(destName).Delete(context.TODO(), httpRG.Name, metav1.DeleteOptions{})).To(Succeed())
// Expect client not to reach server
cond = Td.WaitForRepeatedSuccess(func() bool {
result := Td.HTTPRequest(clientToServer)
// Curl exit code 7 == Conn refused
if result.Err == nil || !strings.Contains(result.Err.Error(), "command terminated with exit code 7 ") {
Td.T.Logf("> (%s) HTTP Req failed, incorrect expected result: %d, %v", srcToDestStr, result.StatusCode, result.Err)
return false
}
Td.T.Logf("> (%s) HTTP Req failed correctly: %v", srcToDestStr, result.Err)
return true
}, 5, 150*time.Second)
Expect(cond).To(BeTrue())
})
}
// setupSource sets up a curl source service and returns the pod object
func setupSource(sourceName string, withKubernetesService bool) *v1.Pod {
var svcAccDef v1.ServiceAccount
var podDef v1.Pod
var svcDef v1.Service
var err error
if Td.ClusterOS == constants.OSWindows {
svcAccDef, podDef, svcDef, err = Td.SimplePodApp(SimplePodAppDef{
PodName: sourceName,
Namespace: sourceName,
Command: []string{"cmd", "/c"},
Args: []string{"FOR /L %N IN () DO ping -n 30 127.0.0.1> nul"},
Image: WindowsNanoserverDockerImage,
Ports: []int{80},
OS: Td.ClusterOS,
})
} else {
// Get simple Pod definitions for the client
svcAccDef, podDef, svcDef, err = Td.SimplePodApp(SimplePodAppDef{
PodName: sourceName,
Namespace: sourceName,
Command: []string{"sleep", "365d"},
Image: "curlimages/curl",
Ports: []int{80},
OS: Td.ClusterOS,
})
}
Expect(err).NotTo(HaveOccurred())
_, err = Td.CreateServiceAccount(sourceName, &svcAccDef)
Expect(err).NotTo(HaveOccurred())
srcPod, err := Td.CreatePod(sourceName, podDef)
Expect(err).NotTo(HaveOccurred())
// In some cases we may want to skip the creation of a Kubernetes service for the source.
if withKubernetesService {
_, err = Td.CreateService(sourceName, svcDef)
Expect(err).NotTo(HaveOccurred())
}
// Expect it to be up and running in it's receiver namespace
Expect(Td.WaitForPodsRunningReady(sourceName, Td.PodDeploymentTimeout, 1, nil)).To(Succeed())
return srcPod
}
// setupFortioSource sets up a Fortio source service and returns the pod object
func setupFortioSource(sourceName string, withKubernetesService bool) *v1.Pod {
var svcAccDef v1.ServiceAccount
var podDef v1.Pod
var svcDef v1.Service
var err error
if Td.ClusterOS == constants.OSWindows {
svcAccDef, podDef, svcDef, err = Td.SimplePodApp(SimplePodAppDef{
PodName: sourceName,
Namespace: sourceName,
Command: []string{"cmd", "/c"},
Args: []string{"FOR /L %N IN () DO ping -n 30 127.0.0.1> nul"},
Image: WindowsNanoserverDockerImage,
Ports: []int{80},
OS: Td.ClusterOS,
})
} else {
// Get simple Pod definitions for the client
svcAccDef, podDef, svcDef, err = Td.SimplePodApp(SimplePodAppDef{
PodName: sourceName,
Namespace: sourceName,
Image: fortioImageName,
Ports: []int{fortioHTTPPort},
OS: Td.ClusterOS,
})
}
Expect(err).NotTo(HaveOccurred())
_, err = Td.CreateServiceAccount(sourceName, &svcAccDef)
Expect(err).NotTo(HaveOccurred())
srcPod, err := Td.CreatePod(sourceName, podDef)
Expect(err).NotTo(HaveOccurred())
// In some cases we may want to skip the creation of a Kubernetes service for the source.
if withKubernetesService {
_, err = Td.CreateService(sourceName, svcDef)
Expect(err).NotTo(HaveOccurred())
}
// Expect it to be up and running in it's receiver namespace
Expect(Td.WaitForPodsRunningReady(sourceName, Td.PodDeploymentTimeout, 1, nil)).To(Succeed())
return srcPod
}