Skip to content

Commit f1931d9

Browse files
authored
Added test for HTTP tunneling (#10695)
1 parent c6489e0 commit f1931d9

File tree

11 files changed

+379
-1
lines changed

11 files changed

+379
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
changelog:
2+
- type: NON_USER_FACING
3+
description: Add a test for HTTP tunneling.
4+

test/kubernetes/e2e/defaults/defaults.go

+17
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,25 @@ import (
88

99
"github.com/solo-io/gloo/pkg/utils/kubeutils/kubectl"
1010
"github.com/solo-io/skv2/codegen/util"
11+
12+
_ "embed"
1113
)
1214

15+
//go:embed testdata/curl_pod.yaml
16+
var CurlPodYaml []byte
17+
18+
//go:embed testdata/http_echo.yaml
19+
var HttpEchoPodYaml []byte
20+
21+
//go:embed testdata/tcp_echo.yaml
22+
var TcpEchoPodYaml []byte
23+
24+
//go:embed testdata/nginx_pod.yaml
25+
var NginxPodYaml []byte
26+
27+
//go:embed testdata/httpbin.yaml
28+
var HttpbinYaml []byte
29+
1330
var (
1431
CurlPodExecOpt = kubectl.PodExecOptions{
1532
Name: "curl",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
apiVersion: v1
3+
kind: Namespace
4+
metadata:
5+
name: httpbin
6+
---
7+
apiVersion: v1
8+
kind: Pod
9+
metadata:
10+
name: httpbin
11+
namespace: httpbin
12+
labels:
13+
app: httpbin
14+
spec:
15+
containers:
16+
- name: httpbin
17+
image: mccutchen/go-httpbin:v2.14.0
18+
ports:
19+
- containerPort: 8080
20+
name: http
21+
---
22+
apiVersion: v1
23+
kind: Service
24+
metadata:
25+
name: httpbin
26+
namespace: httpbin
27+
spec:
28+
ports:
29+
- name: http
30+
port: 8080
31+
targetPort: http
32+
selector:
33+
app: httpbin
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package http_tunnel
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"regexp"
8+
"time"
9+
10+
"github.com/stretchr/testify/suite"
11+
12+
"github.com/solo-io/gloo/pkg/utils/kubeutils"
13+
"github.com/solo-io/gloo/pkg/utils/requestutils/curl"
14+
"github.com/solo-io/gloo/projects/gateway/pkg/defaults"
15+
"github.com/solo-io/gloo/test/gomega/matchers"
16+
"github.com/solo-io/gloo/test/kubernetes/e2e"
17+
testDefaults "github.com/solo-io/gloo/test/kubernetes/e2e/defaults"
18+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19+
20+
_ "embed"
21+
)
22+
23+
const (
24+
httpbinExampleCom = "httpbin.example.com"
25+
)
26+
27+
var _ e2e.NewSuiteFunc = NewTestingSuite
28+
29+
//go:embed testdata/squid.yaml
30+
var squidYaml []byte
31+
32+
//go:embed testdata/proxy.yaml
33+
var proxyYaml []byte
34+
35+
//go:embed testdata/edge.yaml
36+
var edgeYaml []byte
37+
38+
//go:embed testdata/gateway.yaml
39+
var gatewayYaml []byte
40+
41+
// testingSuite is the entire Suite of tests for the HTTP Tunnel feature
42+
type testingSuite struct {
43+
suite.Suite
44+
ctx context.Context
45+
testInstallation *e2e.TestInstallation
46+
}
47+
48+
func NewTestingSuite(
49+
ctx context.Context,
50+
testInst *e2e.TestInstallation,
51+
) suite.TestingSuite {
52+
return &testingSuite{
53+
ctx: ctx,
54+
testInstallation: testInst,
55+
}
56+
}
57+
58+
func (s *testingSuite) SetupSuite() {
59+
err := s.testInstallation.Actions.Kubectl().Apply(s.ctx, squidYaml)
60+
s.Require().NoError(err)
61+
62+
err = s.testInstallation.Actions.Kubectl().Apply(s.ctx, testDefaults.HttpbinYaml)
63+
s.Require().NoError(err)
64+
65+
err = s.testInstallation.Actions.Kubectl().Apply(s.ctx, testDefaults.CurlPodYaml)
66+
s.Require().NoError(err)
67+
68+
err = s.testInstallation.Actions.Kubectl().Apply(s.ctx, proxyYaml)
69+
s.Require().NoError(err)
70+
71+
if s.testInstallation.Metadata.K8sGatewayEnabled {
72+
err = s.testInstallation.Actions.Kubectl().Apply(s.ctx, gatewayYaml)
73+
s.Require().NoError(err)
74+
} else {
75+
err = s.testInstallation.Actions.Kubectl().Apply(s.ctx, edgeYaml)
76+
s.Require().NoError(err)
77+
}
78+
}
79+
80+
func (s *testingSuite) TearDownSuite() {
81+
if s.testInstallation.Metadata.K8sGatewayEnabled {
82+
err := s.testInstallation.Actions.Kubectl().Delete(s.ctx, gatewayYaml)
83+
s.Require().NoError(err)
84+
} else {
85+
err := s.testInstallation.Actions.Kubectl().Delete(s.ctx, edgeYaml)
86+
s.Require().NoError(err)
87+
}
88+
89+
err := s.testInstallation.Actions.Kubectl().Delete(s.ctx, proxyYaml)
90+
s.Require().NoError(err)
91+
92+
err = s.testInstallation.Actions.Kubectl().Delete(s.ctx, testDefaults.CurlPodYaml)
93+
s.Require().NoError(err)
94+
95+
err = s.testInstallation.Actions.Kubectl().Delete(s.ctx, testDefaults.HttpbinYaml)
96+
s.Require().NoError(err)
97+
98+
err = s.testInstallation.Actions.Kubectl().Delete(s.ctx, squidYaml)
99+
s.Require().NoError(err)
100+
}
101+
102+
func (s *testingSuite) AfterTest(suiteName, testName string) {
103+
if s.T().Failed() {
104+
s.testInstallation.PreFailHandler(s.ctx, e2e.PreFailHandlerOption{
105+
TestName: testName,
106+
})
107+
}
108+
}
109+
110+
func (s *testingSuite) TestHttpTunnel() {
111+
opts := []curl.Option{
112+
curl.WithHostHeader(httpbinExampleCom),
113+
curl.WithPath("/headers"),
114+
}
115+
if s.testInstallation.Metadata.K8sGatewayEnabled {
116+
opts = append(opts,
117+
curl.WithHost(kubeutils.ServiceFQDN(metav1.ObjectMeta{
118+
Name: "gloo-proxy-gw",
119+
Namespace: "default",
120+
})),
121+
)
122+
} else {
123+
opts = append(opts,
124+
curl.WithHost(kubeutils.ServiceFQDN(metav1.ObjectMeta{
125+
Name: defaults.GatewayProxyName,
126+
Namespace: s.testInstallation.Metadata.InstallNamespace,
127+
})),
128+
curl.WithPort(80),
129+
)
130+
}
131+
132+
// confirm that the httpbin service is reachable
133+
s.testInstallation.AssertionsT(s.T()).AssertEventualCurlResponse(
134+
s.ctx,
135+
testDefaults.CurlPodExecOpt,
136+
opts,
137+
&matchers.HttpResponse{
138+
StatusCode: http.StatusOK,
139+
Body: matchers.JSONContains([]byte(`{"headers":{"Host":["httpbin.example.com"]}}`)),
140+
},
141+
)
142+
143+
// confirm that the squid proxy connected to the httpbin service
144+
s.testInstallation.AssertionsT(s.T()).Assert.Eventually(func() bool {
145+
logs, err := s.testInstallation.Actions.Kubectl().GetContainerLogs(s.ctx, "default", "squid")
146+
if err != nil {
147+
fmt.Printf("Error getting squid logs: %v\n", err)
148+
return false
149+
}
150+
151+
pattern := "TCP_TUNNEL/200 [0-9]+ CONNECT httpbin.httpbin.svc.cluster.local:8080"
152+
match, err := regexp.Match(pattern, []byte(logs))
153+
if err != nil {
154+
fmt.Printf("Error matching squid logs: %v\n", err)
155+
return false
156+
}
157+
158+
return match
159+
}, time.Second*30, time.Second*3, "squid logs should indicate a connection to the httpbin service")
160+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
apiVersion: gateway.solo.io/v1
3+
kind: VirtualService
4+
metadata:
5+
name: squid-proxy
6+
namespace: default
7+
spec:
8+
virtualHost:
9+
domains:
10+
- 'httpbin.example.com'
11+
routes:
12+
- matchers:
13+
- prefix: /
14+
routeAction:
15+
single:
16+
upstream:
17+
name: squid-proxy
18+
namespace: default
19+
options:
20+
autoHostRewrite: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
kind: Gateway
3+
apiVersion: gateway.networking.k8s.io/v1
4+
metadata:
5+
name: gw
6+
spec:
7+
gatewayClassName: gloo-gateway
8+
listeners:
9+
- protocol: HTTP
10+
port: 8080
11+
name: http
12+
allowedRoutes:
13+
namespaces:
14+
from: Same
15+
---
16+
apiVersion: gateway.solo.io/v1
17+
kind: RouteOption
18+
metadata:
19+
name: rewrite
20+
spec:
21+
options:
22+
hostRewrite: httpbin.example.com
23+
---
24+
apiVersion: gateway.networking.k8s.io/v1
25+
kind: HTTPRoute
26+
metadata:
27+
name: static-upstream
28+
spec:
29+
parentRefs:
30+
- name: gw
31+
hostnames:
32+
- httpbin.example.com
33+
rules:
34+
- backendRefs:
35+
- name: squid-proxy
36+
kind: Upstream
37+
group: gloo.solo.io
38+
filters:
39+
- type: ExtensionRef
40+
extensionRef:
41+
group: gateway.solo.io
42+
kind: RouteOption
43+
name: rewrite
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
apiVersion: gloo.solo.io/v1
3+
kind: Upstream
4+
metadata:
5+
name: squid-proxy
6+
namespace: default
7+
spec:
8+
static:
9+
hosts:
10+
- addr: squid.default.svc.cluster.local
11+
port: 3128
12+
httpProxyHostname: "httpbin.httpbin.svc.cluster.local:8080"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
apiVersion: v1
3+
kind: Pod
4+
metadata:
5+
name: squid
6+
labels:
7+
app: squid
8+
spec:
9+
volumes:
10+
- name: squid-config
11+
configMap:
12+
name: squid-config
13+
containers:
14+
- name: squid-container
15+
image: ubuntu/squid:5.2-22.04_beta
16+
env:
17+
- name: TZ
18+
value: "UTC"
19+
ports:
20+
- containerPort: 3128
21+
volumeMounts:
22+
- name: squid-config
23+
mountPath: /etc/squid/squid.conf
24+
subPath: squid.conf
25+
---
26+
apiVersion: v1
27+
kind: Service
28+
metadata:
29+
name: squid
30+
spec:
31+
selector:
32+
app: squid
33+
ports:
34+
- protocol: TCP
35+
port: 3128
36+
targetPort: 3128
37+
---
38+
apiVersion: v1
39+
kind: ConfigMap
40+
metadata:
41+
name: squid-config
42+
data:
43+
squid.conf: |
44+
acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
45+
acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
46+
acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
47+
acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
48+
acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN)
49+
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
50+
acl localnet src fc00::/7 # RFC 4193 local private network range
51+
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
52+
acl SSL_ports port 443
53+
acl Safe_ports port 80 # http
54+
acl Safe_ports port 21 # ftp
55+
acl Safe_ports port 443 # https
56+
acl Safe_ports port 70 # gopher
57+
acl Safe_ports port 210 # wais
58+
acl Safe_ports port 1025-65535 # unregistered ports
59+
acl Safe_ports port 280 # http-mgmt
60+
acl Safe_ports port 488 # gss-http
61+
acl Safe_ports port 591 # filemaker
62+
acl Safe_ports port 777 # multiling http
63+
acl CONNECT method CONNECT
64+
http_access deny !Safe_ports
65+
#commented out to allow non-TSL connections
66+
#http_access deny CONNECT !SSL_ports
67+
http_access allow localhost manager
68+
http_access deny manager
69+
http_access allow localhost
70+
http_access allow localnet
71+
http_access deny all
72+
http_port 3128
73+
coredump_dir /var/spool/squid
74+
refresh_pattern ^ftp: 1440 20% 10080
75+
refresh_pattern ^gopher: 1440 0% 1440
76+
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
77+
refresh_pattern \/(Packages|Sources)(|\.bz2|\.gz|\.xz)$ 0 0% 0 refresh-ims
78+
refresh_pattern \/Release(|\.gpg)$ 0 0% 0 refresh-ims
79+
refresh_pattern \/InRelease$ 0 0% 0 refresh-ims
80+
refresh_pattern \/(Translation-.*)(|\.bz2|\.gz|\.xz)$ 0 0% 0 refresh-ims
81+
refresh_pattern . 0 20% 4320
82+
logfile_rotate 0

0 commit comments

Comments
 (0)