From a6a1c9179d1172e34d06bf12c671cbff38a5d9f6 Mon Sep 17 00:00:00 2001 From: Daniel Tomcej Date: Mon, 24 Feb 2020 07:48:07 -0800 Subject: [PATCH] Mergeback v1.1 rc2 --- .semaphoreci/golang.sh | 20 -- .semaphoreci/job1.sh | 4 - .semaphoreci/job2.sh | 4 - .semaphoreci/setup.sh | 32 --- .semaphoreci/vars | 34 --- docs/content/configuration.md | 3 + docs/content/examples.md | 63 ++++ helm/chart/maesh/Chart.yaml | 4 +- integration/resources/smi/access-control.json | 6 +- integration/resources/smi/traffic-split.json | 10 +- .../build_configuration_multiple_ports.yaml | 45 +++ ...uild_configuration_multiple_ports_tcp.yaml | 47 +++ pkg/providers/kubernetes/provider.go | 16 +- pkg/providers/kubernetes/provider_test.go | 271 +++++++++++++++++- pkg/providers/smi/provider.go | 13 +- pkg/providers/smi/provider_test.go | 16 +- 16 files changed, 471 insertions(+), 117 deletions(-) delete mode 100755 .semaphoreci/golang.sh delete mode 100755 .semaphoreci/job1.sh delete mode 100755 .semaphoreci/job2.sh delete mode 100755 .semaphoreci/setup.sh delete mode 100644 .semaphoreci/vars create mode 100644 pkg/providers/kubernetes/fixtures/build_configuration_multiple_ports.yaml create mode 100644 pkg/providers/kubernetes/fixtures/build_configuration_multiple_ports_tcp.yaml diff --git a/.semaphoreci/golang.sh b/.semaphoreci/golang.sh deleted file mode 100755 index f2705f81f..000000000 --- a/.semaphoreci/golang.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -set -e - -curl -O https://dl.google.com/go/go"${GO_VERSION}".linux-amd64.tar.gz - -tar -xvf go"${GO_VERSION}".linux-amd64.tar.gz -rm -rf go"${GO_VERSION}".linux-amd64.tar.gz - -sudo mkdir -p /usr/local/golang/"${GO_VERSION}"/go -sudo mv go /usr/local/golang/"${GO_VERSION}"/ - -sudo rm -rf /usr/local/bin/go || exit 1 -sudo chmod +x /usr/local/golang/"${GO_VERSION}"/go/bin/go -sudo ln -s /usr/local/golang/"${GO_VERSION}"/go/bin/go /usr/local/bin/go - -export GOROOT="/usr/local/golang/${GO_VERSION}/go" -export GOTOOLDIR="/usr/local/golang/${GO_VERSION}/go/pkg/tool/linux_amd64" - -go version diff --git a/.semaphoreci/job1.sh b/.semaphoreci/job1.sh deleted file mode 100755 index f8aecc3d9..000000000 --- a/.semaphoreci/job1.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -e - -make diff --git a/.semaphoreci/job2.sh b/.semaphoreci/job2.sh deleted file mode 100755 index ff91b322c..000000000 --- a/.semaphoreci/job2.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -e - -if [ -n "$SHOULD_TEST" ]; then ci_retry make test-integration; fi diff --git a/.semaphoreci/setup.sh b/.semaphoreci/setup.sh deleted file mode 100755 index eb93cd751..000000000 --- a/.semaphoreci/setup.sh +++ /dev/null @@ -1,32 +0,0 @@ -# For personnal CI -for s in apache2 cassandra elasticsearch memcached mysql mongod postgresql sphinxsearch rethinkdb rabbitmq-server redis-server; do sudo service $s stop; done -sudo swapoff -a -sudo dd if=/dev/zero of=/swapfile bs=1M count=3072 -sudo mkswap /swapfile -sudo swapon /swapfile -sudo rm -rf /home/runner/.rbenv -sudo rm -rf /usr/local/golang/{1.4.3,1.5.4,1.6.4,1.7.6,1.8.6,1.9.7,1.10.3,1.11} -source .semaphoreci/vars -if [ -z "${PULL_REQUEST_NUMBER}" ]; then SHOULD_TEST="-*-"; else TEMP_STORAGE=$(curl --silent https://patch-diff.githubusercontent.com/raw/containous/maesh/pull/"${PULL_REQUEST_NUMBER}".diff | patch --dry-run -p1 -R || true); fi -echo "${SHOULD_TEST}" -if [ -n "${TEMP_STORAGE}" ]; then SHOULD_TEST=$(echo "${TEMP_STORAGE}" | grep -Ev '(.md|.yaml|.yml)' || :); fi -echo "${TEMP_STORAGE}" -echo "${SHOULD_TEST}" -if [ -n "$SHOULD_TEST" ]; then docker version; fi - -export GO_VERSION=1.12 -if [ -f "./go.mod" ]; then GO_VERSION="$(grep '^go .*' go.mod | awk '{print $2}')"; export GO_VERSION; fi -echo "Selected Go version: ${GO_VERSION}" - -if [ -f "./.semaphoreci/golang.sh" ]; then ./.semaphoreci/golang.sh; fi -if [ -f "./.semaphoreci/golang.sh" ]; then export GOROOT="/usr/local/golang/${GO_VERSION}/go"; fi -if [ -f "./.semaphoreci/golang.sh" ]; then export GOTOOLDIR="/usr/local/golang/${GO_VERSION}/go/pkg/tool/linux_amd64"; fi -go version -mkdir -p /home/runner/src/github.com/containous -cp -r /home/runner/maesh /home/runner/src/github.com/containous -cd /home/runner/src/github.com/containous/maesh -if [ -f "./go.mod" ]; then export GO111MODULE=on; fi -if [ -f "./go.mod" ]; then export GOPROXY=https://proxy.golang.org; fi -if [ -f "./go.mod" ]; then go mod download; fi - -df diff --git a/.semaphoreci/vars b/.semaphoreci/vars deleted file mode 100644 index 7fdaae102..000000000 --- a/.semaphoreci/vars +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -set -e - -export REPO='containous/maesh' - -if VERSION=$(git describe --exact-match --abbrev=0 --tags); -then - export VERSION -else - export VERSION='' -fi - -export N_MAKE_JOBS=2 - - -function ci_retry { - - local NRETRY=3 - local NSLEEP=5 - local n=0 - - until [ $n -ge $NRETRY ] - do - "$@" && break - n=$((n+1)) - echo "${*} failed, attempt ${n}/${NRETRY}" - sleep $NSLEEP - done - - [ $n -lt $NRETRY ] - -} - -export -f ci_retry diff --git a/docs/content/configuration.md b/docs/content/configuration.md index e9a9f97c3..3b341b0b3 100644 --- a/docs/content/configuration.md +++ b/docs/content/configuration.md @@ -125,6 +125,9 @@ Other types of route groups and detailed information are available [in the speci By default, all traffic is denied so we need to grant access to clients to our application. This is done by defining a `TrafficTarget`. +??? Note "TrafficTarget Source & Destination" + Please note that TrafficTarget is a namespaced resource. Therefore, the source and the destination namespace needs to be explicitly defined. + ```yaml --- apiVersion: access.smi-spec.io/v1alpha1 diff --git a/docs/content/examples.md b/docs/content/examples.md index cc426c842..52d6b24cd 100644 --- a/docs/content/examples.md +++ b/docs/content/examples.md @@ -242,3 +242,66 @@ User-Agent: curl/7.64.0 Accept: */* X-Forwarded-For: 3.4.5.6 ``` + +## SMI Example + +In order to expose the HTTP Services from above with SMI enabled, please create the following resources: + +```yaml +--- +apiVersion: specs.smi-spec.io/v1alpha1 +kind: HTTPRouteGroup +metadata: + name: http-everything + namespace: whoami +matches: +- name: everything + pathRegex: ".*" + methods: ["*"] +--- +kind: TrafficTarget +apiVersion: access.smi-spec.io/v1alpha1 +metadata: + name: whatever + namespace: whoami +destination: + kind: ServiceAccount + name: whoami-server + namespace: whoami + port: "80" +specs: +- kind: HTTPRouteGroup + name: http-everything + matches: + - everything +sources: +- kind: ServiceAccount + name: whoami-client + namespace: whoami +``` + +For TCP mode, you only need a TCPRoute and a TrafficTarget: + +```yaml +kind: TrafficTarget +apiVersion: access.smi-spec.io/v1alpha1 +metadata: + name: api-service-target + namespace: default +destination: + kind: ServiceAccount + name: api-service + namespace: default +specs: +- kind: TCPRoute + name: my-tcp-route +sources: +- kind: ServiceAccount + name: my-other-service + namespace: default +--- +apiVersion: specs.smi-spec.io/v1alpha1 +kind: TCPRoute +metadata: + name: my-tcp-route +``` diff --git a/helm/chart/maesh/Chart.yaml b/helm/chart/maesh/Chart.yaml index 3db965fbe..fcaa4db54 100644 --- a/helm/chart/maesh/Chart.yaml +++ b/helm/chart/maesh/Chart.yaml @@ -1,8 +1,8 @@ --- apiVersion: v2 name: maesh -version: 1.1.0-rc1 -appVersion: v1.1.0-rc1 +version: 1.1.0-rc2 +appVersion: v1.1.0-rc2 description: Maesh - Simpler Service Mesh keywords: - traefik diff --git a/integration/resources/smi/access-control.json b/integration/resources/smi/access-control.json index aeb1772fc..7f02a729c 100644 --- a/integration/resources/smi/access-control.json +++ b/integration/resources/smi/access-control.json @@ -9,7 +9,7 @@ "a-b-test-b-test-80-a-b-test-e0425d13b2a322ad-whitelist" ], "service": "b-test-80-a-b-test-e0425d13b2a322ad", - "rule": "(PathPrefix(`/foo`) \u0026\u0026 (Host(`b.test.maesh`) || Host(`10.43.233.50`)))" + "rule": "(PathPrefix(`/{path:foo}`) \u0026\u0026 (Host(`b.test.maesh`) || Host(`10.43.233.50`)))" }, "b-test-80-c-b-test-643c7128c8514ba9": { "entryPoints": [ @@ -19,7 +19,7 @@ "c-b-test-b-test-80-c-b-test-643c7128c8514ba9-whitelist" ], "service": "b-test-80-c-b-test-643c7128c8514ba9", - "rule": "(PathPrefix(`/foo`) \u0026\u0026 (Host(`b.test.maesh`) || Host(`10.43.233.50`)))" + "rule": "(PathPrefix(`/{path:foo}`) \u0026\u0026 (Host(`b.test.maesh`) || Host(`10.43.233.50`)))" }, "d-test-80-c-d-test-2c7d96b07eb597fd": { "entryPoints": [ @@ -29,7 +29,7 @@ "c-d-test-d-test-80-c-d-test-2c7d96b07eb597fd-whitelist" ], "service": "d-test-80-c-d-test-2c7d96b07eb597fd", - "rule": "(PathPrefix(`/bar`) \u0026\u0026 (Host(`d.test.maesh`) || Host(`10.43.86.23`)))" + "rule": "(PathPrefix(`/{path:bar}`) \u0026\u0026 (Host(`d.test.maesh`) || Host(`10.43.86.23`)))" }, "readiness": { "entryPoints": [ diff --git a/integration/resources/smi/traffic-split.json b/integration/resources/smi/traffic-split.json index b07bbafa8..911b41c7e 100644 --- a/integration/resources/smi/traffic-split.json +++ b/integration/resources/smi/traffic-split.json @@ -9,7 +9,7 @@ "a-b-test-b-test-80-a-b-test-e0425d13b2a322ad-whitelist" ], "service": "b-test-80-a-b-test-e0425d13b2a322ad", - "rule": "(PathPrefix(`/foo`) \u0026\u0026 (Host(`b.test.maesh`) || Host(`XXXX`)))" + "rule": "(PathPrefix(`/{path:foo}`) \u0026\u0026 (Host(`b.test.maesh`) || Host(`XXXX`)))" }, "b-v1-test-80-a-b-test-03b338bc8ba21fbc": { "entryPoints": [ @@ -19,7 +19,7 @@ "a-b-test-b-v1-test-80-a-b-test-03b338bc8ba21fbc-whitelist" ], "service": "b-v1-test-80-a-b-test-03b338bc8ba21fbc", - "rule": "(PathPrefix(`/foo`) \u0026\u0026 (Host(`b-v1.test.maesh`) || Host(`XXXX`)))" + "rule": "(PathPrefix(`/{path:foo}`) \u0026\u0026 (Host(`b-v1.test.maesh`) || Host(`XXXX`)))" }, "b-v2-test-80-a-b-test-c2918aa87de2f415": { "entryPoints": [ @@ -29,7 +29,7 @@ "a-b-test-b-v2-test-80-a-b-test-c2918aa87de2f415-whitelist" ], "service": "b-v2-test-80-a-b-test-c2918aa87de2f415", - "rule": "(PathPrefix(`/foo`) \u0026\u0026 (Host(`b-v2.test.maesh`) || Host(`XXXX`)))" + "rule": "(PathPrefix(`/{path:foo}`) \u0026\u0026 (Host(`b-v2.test.maesh`) || Host(`XXXX`)))" }, "b1-test-80-a-b-test-ce97b257f9b2710f": { "entryPoints": [ @@ -39,7 +39,7 @@ "a-b-test-b1-test-80-a-b-test-ce97b257f9b2710f-whitelist" ], "service": "b1-test-80-a-b-test-ce97b257f9b2710f", - "rule": "(PathPrefix(`/foo`) \u0026\u0026 (Host(`b1.test.maesh`) || Host(`XXXX`)))" + "rule": "(PathPrefix(`/{path:foo}`) \u0026\u0026 (Host(`b1.test.maesh`) || Host(`XXXX`)))" }, "b2-test-80-a-b-test-6485fb29d873a5c3": { "entryPoints": [ @@ -49,7 +49,7 @@ "a-b-test-b2-test-80-a-b-test-6485fb29d873a5c3-whitelist" ], "service": "b2-test-80-a-b-test-6485fb29d873a5c3", - "rule": "(PathPrefix(`/foo`) \u0026\u0026 (Host(`b2.test.maesh`) || Host(`XXXX`)))" + "rule": "(PathPrefix(`/{path:foo}`) \u0026\u0026 (Host(`b2.test.maesh`) || Host(`XXXX`)))" }, "readiness": { "entryPoints": [ diff --git a/pkg/providers/kubernetes/fixtures/build_configuration_multiple_ports.yaml b/pkg/providers/kubernetes/fixtures/build_configuration_multiple_ports.yaml new file mode 100644 index 000000000..7be9736ff --- /dev/null +++ b/pkg/providers/kubernetes/fixtures/build_configuration_multiple_ports.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: foo +--- +apiVersion: v1 +kind: Service +metadata: + name: test + namespace: foo +spec: + clusterIP: 10.1.0.1 + selector: + app: test + ports: + - protocol: TCP + port: 80 + targetPort: 80 + - protocol: TCP + port: 443 + targetPort: 443 +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: test + namespace: foo +subsets: +- addresses: + - ip: 10.0.0.1 + ports: + - port: 80 +- addresses: + - ip: 10.0.0.2 + ports: + - port: 80 +- addresses: + - ip: 10.0.0.3 + ports: + - port: 443 +- addresses: + - ip: 10.0.0.4 + ports: + - port: 443 + \ No newline at end of file diff --git a/pkg/providers/kubernetes/fixtures/build_configuration_multiple_ports_tcp.yaml b/pkg/providers/kubernetes/fixtures/build_configuration_multiple_ports_tcp.yaml new file mode 100644 index 000000000..1825772dc --- /dev/null +++ b/pkg/providers/kubernetes/fixtures/build_configuration_multiple_ports_tcp.yaml @@ -0,0 +1,47 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: foo +--- +apiVersion: v1 +kind: Service +metadata: + name: test + namespace: foo + annotations: + maesh.containo.us/traffic-type: tcp +spec: + clusterIP: 10.1.0.1 + selector: + app: test + ports: + - protocol: TCP + port: 80 + targetPort: 80 + - protocol: TCP + port: 443 + targetPort: 443 +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: test + namespace: foo +subsets: +- addresses: + - ip: 10.0.0.1 + ports: + - port: 80 +- addresses: + - ip: 10.0.0.2 + ports: + - port: 80 +- addresses: + - ip: 10.0.0.3 + ports: + - port: 443 +- addresses: + - ip: 10.0.0.4 + ports: + - port: 443 + diff --git a/pkg/providers/kubernetes/provider.go b/pkg/providers/kubernetes/provider.go index 8c40e94d0..93c49f2b6 100644 --- a/pkg/providers/kubernetes/provider.go +++ b/pkg/providers/kubernetes/provider.go @@ -71,12 +71,16 @@ func (p *Provider) buildTCPRouter(port int, serviceName string) *dynamic.TCPRout } } -func (p *Provider) buildService(endpoints *corev1.Endpoints, scheme string) *dynamic.Service { +func (p *Provider) buildService(endpoints *corev1.Endpoints, scheme string, servicePort int32) *dynamic.Service { var servers []dynamic.Server if endpoints != nil && endpoints.Subsets != nil { for _, subset := range endpoints.Subsets { for _, endpointPort := range subset.Ports { + if endpointPort.Port != servicePort { + continue + } + for _, address := range subset.Addresses { server := dynamic.Server{ URL: fmt.Sprintf("%s://%s", scheme, net.JoinHostPort(address.IP, strconv.FormatInt(int64(endpointPort.Port), 10))), @@ -97,12 +101,16 @@ func (p *Provider) buildService(endpoints *corev1.Endpoints, scheme string) *dyn } } -func (p *Provider) buildTCPService(endpoints *corev1.Endpoints) *dynamic.TCPService { +func (p *Provider) buildTCPService(endpoints *corev1.Endpoints, servicePort int32) *dynamic.TCPService { var servers []dynamic.TCPServer if endpoints != nil && endpoints.Subsets != nil { for _, subset := range endpoints.Subsets { for _, endpointPort := range subset.Ports { + if endpointPort.Port != servicePort { + continue + } + for _, address := range subset.Addresses { server := dynamic.TCPServer{ Address: net.JoinHostPort(address.IP, strconv.FormatInt(int64(endpointPort.Port), 10)), @@ -149,7 +157,7 @@ func (p *Provider) BuildConfig() (*dynamic.Configuration, error) { key := buildKey(service.Name, service.Namespace, sp.Port) if serviceMode == k8s.ServiceTypeHTTP { - config.HTTP.Services[key] = p.buildService(base.GetEndpointsFromList(service.Name, service.Namespace, endpoints), scheme) + config.HTTP.Services[key] = p.buildService(base.GetEndpointsFromList(service.Name, service.Namespace, endpoints), scheme, sp.Port) middlewares := p.buildHTTPMiddlewares(service.Annotations) if middlewares != nil { @@ -166,7 +174,7 @@ func (p *Provider) BuildConfig() (*dynamic.Configuration, error) { meshPort := p.getMeshPort(service.Name, service.Namespace, sp.Port) config.TCP.Routers[key] = p.buildTCPRouter(meshPort, key) - config.TCP.Services[key] = p.buildTCPService(base.GetEndpointsFromList(service.Name, service.Namespace, endpoints)) + config.TCP.Services[key] = p.buildTCPService(base.GetEndpointsFromList(service.Name, service.Namespace, endpoints), sp.Port) } } diff --git a/pkg/providers/kubernetes/provider_test.go b/pkg/providers/kubernetes/provider_test.go index 9f69e6681..4aa982de3 100644 --- a/pkg/providers/kubernetes/provider_test.go +++ b/pkg/providers/kubernetes/provider_test.go @@ -78,6 +78,11 @@ func TestBuildConfiguration(t *testing.T) { Namespace: "foo", Port: 80, }, + 10001: { + Name: "test", + Namespace: "foo", + Port: 443, + }, }, } @@ -144,6 +149,158 @@ func TestBuildConfiguration(t *testing.T) { }, }, }, + { + desc: "simple configuration build with multiple port service", + mockFile: "build_configuration_multiple_ports.yaml", + expected: &dynamic.Configuration{ + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{ + "readiness": { + EntryPoints: []string{"readiness"}, + Service: "readiness", + Rule: "Path(`/ping`)", + }, + "test-foo-80-6653beb49ee354ea": { + EntryPoints: []string{"http-5000"}, + Service: "test-foo-80-6653beb49ee354ea", + Rule: "Host(`test.foo.maesh`) || Host(`10.1.0.1`)", + }, + "test-foo-443-92bb68bb9ffcb54d": { + EntryPoints: []string{"http-5001"}, + Service: "test-foo-443-92bb68bb9ffcb54d", + Rule: "Host(`test.foo.maesh`) || Host(`10.1.0.1`)", + }, + }, + Middlewares: map[string]*dynamic.Middleware{}, + Services: map[string]*dynamic.Service{ + "readiness": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + PassHostHeader: base.Bool(true), + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:8080", + Scheme: "", + Port: "", + }, + }, + }, + }, + "test-foo-80-6653beb49ee354ea": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + PassHostHeader: base.Bool(true), + Servers: []dynamic.Server{ + { + URL: "http://10.0.0.1:80", + Scheme: "", + Port: "", + }, + { + URL: "http://10.0.0.2:80", + Scheme: "", + Port: "", + }, + }, + }, + }, + "test-foo-443-92bb68bb9ffcb54d": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + PassHostHeader: base.Bool(true), + Servers: []dynamic.Server{ + { + URL: "http://10.0.0.3:443", + Scheme: "", + Port: "", + }, + { + URL: "http://10.0.0.4:443", + Scheme: "", + Port: "", + }, + }, + }, + }, + }, + }, + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{}, + Services: map[string]*dynamic.TCPService{}, + }, + }, + }, + { + desc: "simple configuration build with multiple port TCP service", + mockFile: "build_configuration_multiple_ports_tcp.yaml", + expected: &dynamic.Configuration{ + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{ + "readiness": { + EntryPoints: []string{"readiness"}, + Service: "readiness", + Rule: "Path(`/ping`)", + }, + }, + Middlewares: map[string]*dynamic.Middleware{}, + Services: map[string]*dynamic.Service{ + "readiness": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + PassHostHeader: base.Bool(true), + Servers: []dynamic.Server{ + { + URL: "http://127.0.0.1:8080", + Scheme: "", + Port: "", + }, + }, + }, + }, + }, + }, + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{ + "test-foo-80-6653beb49ee354ea": { + EntryPoints: []string{"tcp-10000"}, + Service: "test-foo-80-6653beb49ee354ea", + Rule: "HostSNI(`*`)", + }, + "test-foo-443-92bb68bb9ffcb54d": { + EntryPoints: []string{"tcp-10001"}, + Service: "test-foo-443-92bb68bb9ffcb54d", + Rule: "HostSNI(`*`)", + }, + }, + Services: map[string]*dynamic.TCPService{ + "test-foo-80-6653beb49ee354ea": { + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{ + { + Address: "10.0.0.1:80", + Port: "", + }, + { + Address: "10.0.0.2:80", + Port: "", + }, + }, + }, + }, + "test-foo-443-92bb68bb9ffcb54d": { + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{ + { + Address: "10.0.0.3:443", + Port: "", + }, + { + Address: "10.0.0.4:443", + Port: "", + }, + }, + }, + }, + }, + }, + }, + }, { desc: "simple configuration build with HTTP service middlewares", mockFile: "build_configuration_simple_http_middlewares.yaml", @@ -374,6 +531,62 @@ func TestBuildService(t *testing.T) { }, }, }, + { + desc: "Multiple Ports", + mockFile: "build_service_simple.yaml", + endpoints: &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "foo", + }, + Subsets: []corev1.EndpointSubset{ + { + Addresses: []corev1.EndpointAddress{ + { + IP: "10.0.0.1", + }, + { + IP: "10.0.0.2", + }, + }, + Ports: []corev1.EndpointPort{ + { + Port: 80, + }, + }, + }, + { + Addresses: []corev1.EndpointAddress{ + { + IP: "10.0.0.3", + }, + { + IP: "10.0.0.4", + }, + }, + Ports: []corev1.EndpointPort{ + { + Port: 443, + }, + }, + }, + }, + }, + scheme: "http", + expected: &dynamic.Service{ + LoadBalancer: &dynamic.ServersLoadBalancer{ + PassHostHeader: base.Bool(true), + Servers: []dynamic.Server{ + { + URL: "http://10.0.0.1:80", + }, + { + URL: "http://10.0.0.2:80", + }, + }, + }, + }, + }, } for _, test := range testCases { @@ -387,7 +600,7 @@ func TestBuildService(t *testing.T) { clientMock := k8s.NewClientMock(ctx.Done(), test.mockFile, false) ignored := k8s.NewIgnored() provider := New(k8s.ServiceTypeHTTP, nil, ignored, clientMock.ServiceLister, clientMock.EndpointsLister) - actual := provider.buildService(test.endpoints, test.scheme) + actual := provider.buildService(test.endpoints, test.scheme, 80) assert.Equal(t, test.expected, actual) }) @@ -450,6 +663,60 @@ func TestBuildTCPService(t *testing.T) { }, }, }, + { + desc: "Multiple ports", + mockFile: "build_service_simple.yaml", + endpoints: &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "foo", + }, + Subsets: []corev1.EndpointSubset{ + { + Addresses: []corev1.EndpointAddress{ + { + IP: "10.0.0.1", + }, + { + IP: "10.0.0.2", + }, + }, + Ports: []corev1.EndpointPort{ + { + Port: 80, + }, + }, + }, + { + Addresses: []corev1.EndpointAddress{ + { + IP: "10.0.0.3", + }, + { + IP: "10.0.0.4", + }, + }, + Ports: []corev1.EndpointPort{ + { + Port: 443, + }, + }, + }, + }, + }, + expected: &dynamic.TCPService{ + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{ + { + Address: "10.0.0.1:80", + }, + { + Address: "10.0.0.2:80", + }, + }, + }, + }, + }, } for _, test := range testCases { @@ -463,7 +730,7 @@ func TestBuildTCPService(t *testing.T) { clientMock := k8s.NewClientMock(ctx.Done(), test.mockFile, false) ignored := k8s.NewIgnored() provider := New(k8s.ServiceTypeHTTP, stateTable, ignored, clientMock.ServiceLister, clientMock.EndpointsLister) - actual := provider.buildTCPService(test.endpoints) + actual := provider.buildTCPService(test.endpoints, 80) assert.Equal(t, test.expected, actual) }) } diff --git a/pkg/providers/smi/provider.go b/pkg/providers/smi/provider.go index dee539bb4..10c670031 100644 --- a/pkg/providers/smi/provider.go +++ b/pkg/providers/smi/provider.go @@ -324,7 +324,7 @@ func (p *Provider) buildHTTPRouterFromTrafficTarget(serviceName, serviceNamespac rawHTTPRouteGroup, err := p.httpRouteGroupLister.HTTPRouteGroups(trafficTarget.Namespace).Get(spec.Name) if err != nil { - log.Errorf("Error getting HTTPRouteGroup: %v", err) + log.Errorf("Error getting the HTTPRouteGroups %s in the same namespace %s as the TrafficTarget: %v", spec.Name, trafficTarget.Namespace, err) continue } @@ -360,7 +360,7 @@ func (p *Provider) buildTCPRouterFromTrafficTarget(trafficTarget *access.Traffic _, err := p.tcpRouteLister.TCPRoutes(trafficTarget.Namespace).Get(spec.Name) if err != nil { - log.Errorf("Error getting TCPRoute: %v", err) + log.Errorf("Error getting the TCPRoute %s in the same namespace %s as the TrafficTarget: %v", spec.Name, trafficTarget.Namespace, err) continue } @@ -376,8 +376,15 @@ func (p *Provider) buildTCPRouterFromTrafficTarget(trafficTarget *access.Traffic func (p *Provider) buildRuleSnippetFromServiceAndMatch(name, namespace, ip string, match specs.HTTPMatch) string { var result []string + if len(match.PathRegex) > 0 { - result = append(result, fmt.Sprintf("PathPrefix(`%s`)", match.PathRegex)) + preparedPath := match.PathRegex + + if strings.HasPrefix(match.PathRegex, "/") { + preparedPath = strings.TrimPrefix(preparedPath, "/") + } + + result = append(result, fmt.Sprintf("PathPrefix(`/{path:%s}`)", preparedPath)) } if len(match.Methods) > 0 && match.Methods[0] != "*" { diff --git a/pkg/providers/smi/provider_test.go b/pkg/providers/smi/provider_test.go index f360beb2b..5c872fad1 100644 --- a/pkg/providers/smi/provider_test.go +++ b/pkg/providers/smi/provider_test.go @@ -38,7 +38,7 @@ func TestBuildRuleSnippetFromServiceAndMatch(t *testing.T) { }{ { desc: "method and regex in match", - expected: "PathPrefix(`/foo`) && Method(`GET`,`POST`) && (Host(`test.foo.maesh`) || Host(`10.0.0.1`))", + expected: "PathPrefix(`/{path:foo}`) && Method(`GET`,`POST`) && (Host(`test.foo.maesh`) || Host(`10.0.0.1`))", match: specsv1alpha1.HTTPMatch{ Name: "test", Methods: []string{"GET", "POST"}, @@ -55,12 +55,20 @@ func TestBuildRuleSnippetFromServiceAndMatch(t *testing.T) { }, { desc: "prefix only in match", - expected: "PathPrefix(`/foo`) && (Host(`test.foo.maesh`) || Host(`10.0.0.1`))", + expected: "PathPrefix(`/{path:foo}`) && (Host(`test.foo.maesh`) || Host(`10.0.0.1`))", match: specsv1alpha1.HTTPMatch{ Name: "test", PathRegex: "/foo", }, }, + { + desc: "prefix only with regex in match", + expected: "PathPrefix(`/{path:.*}`) && (Host(`test.foo.maesh`) || Host(`10.0.0.1`))", + match: specsv1alpha1.HTTPMatch{ + Name: "test", + PathRegex: ".*", + }, + }, } for _, test := range testCases { @@ -219,7 +227,7 @@ func TestBuildHTTPRouterFromTrafficTarget(t *testing.T) { expected: &dynamic.Router{ EntryPoints: []string{"http-81"}, Service: "example", - Rule: "(PathPrefix(`/metrics`) && Method(`GET`) && (Host(`test.default.maesh`) || Host(`10.0.0.1`)))", + Rule: "(PathPrefix(`/{path:metrics}`) && Method(`GET`) && (Host(`test.default.maesh`) || Host(`10.0.0.1`)))", Middlewares: []string{"block-all"}, }, }, @@ -1282,7 +1290,7 @@ func TestBuildConfiguration(t *testing.T) { Routers: map[string]*dynamic.Router{ "demo-servi-default-80-api-servic-default-5bb66e727779b5ba": { EntryPoints: []string{"http-5000"}, - Rule: "(PathPrefix(`/metrics`) && Method(`GET`) && (Host(`demo-service.default.maesh`) || Host(`10.1.0.1`)))", + Rule: "(PathPrefix(`/{path:metrics}`) && Method(`GET`) && (Host(`demo-service.default.maesh`) || Host(`10.1.0.1`)))", Service: "demo-servi-default-80-api-servic-default-5bb66e727779b5ba", Middlewares: []string{"api-service-metrics-default-demo-servi-default-80-api-servic-default-5bb66e727779b5ba-whitelist"}, },