Repository: containous/maesh
Pull request #438 (2020-02-24 14:34:28)

Mergeback v1.1 rc2
This PR:

- Updates the master branch with the updates from v1.1

claassistantio: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/containous/maesh?pullRequest=438) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our [Contributor License Agreement](https://cla-assistant.io/containous/maesh?pullRequest=438) before we can accept your contribution.<br/>**3** out of **4** committers have signed the CLA.<br/><br/>:white_check_mark: dtomcej<br/>:white_check_mark: mmatur<br/>:white_check_mark: SantoDE<br/>:x: traefiker<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/containous/maesh?pullRequest=438) it.</sub>

Patch:
diff --git a/.semaphoreci/golang.sh b/.semaphoreci/golang.sh
deleted file mode 100755
index f2705f8..0000000
--- 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 f8aecc3..0000000
--- 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 ff91b32..0000000
--- 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 eb93cd7..0000000
--- 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 7fdaae1..0000000
--- 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 e9a9f97..3b341b0 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 cc426c8..52d6b24 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 3db965f..fcaa4db 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 aeb1772..7f02a72 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 b07bbaf..911b41c 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 0000000..7be9736
--- /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 0000000..1825772
--- /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 8c40e94..93c49f2 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/smi/provider.go b/pkg/providers/smi/provider.go
index dee539b..10c6700 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] != "*" {


Test patch:
diff --git a/pkg/providers/kubernetes/provider_test.go b/pkg/providers/kubernetes/provider_test.go
index 9f69e66..4aa982d 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_test.go b/pkg/providers/smi/provider_test.go
index f360beb..5c872fa 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"},
 						},