Repository: containous/maesh
Pull request #260 (2019-10-01 21:23:23)

Move SMI provider to be stateless
This PR:

- Updates the SMI provider to be stateless

Todo:

- [x] Update unit tests to handle new provider behavior
- [x] Update build config to request objects as a list instead of requesting objects in loops
- [x] Move duplicated functions like `getEndpointsFromList` and `createBaseConfigWithReadiness` to a package so they are not duplicated


Partially solves #242.

SantoDE: Build fails on semaphore

Patch:
diff --git a/internal/controller/controller.go b/internal/controller/controller.go
index 6873b5a..87d1b61 100644
--- a/internal/controller/controller.go
+++ b/internal/controller/controller.go
@@ -8,6 +8,7 @@ import (
 	"github.com/containous/maesh/internal/deployer"
 	"github.com/containous/maesh/internal/k8s"
 	"github.com/containous/maesh/internal/message"
+	"github.com/containous/maesh/internal/providers/base"
 	"github.com/containous/maesh/internal/providers/kubernetes"
 	"github.com/containous/maesh/internal/providers/smi"
 	"github.com/containous/traefik/v2/pkg/config/dynamic"
@@ -97,7 +98,7 @@ func (c *Controller) Init() error {
 	c.meshFactory.Core().V1().Pods().Informer().AddEventHandler(c.meshHandler)
 
 	c.tcpStateTable = &k8s.State{Table: make(map[int]*k8s.ServiceWithPort)}
-	c.kubernetesProvider = kubernetes.New(c.clients, c.defaultMode, c.meshNamespace, c.tcpStateTable)
+	c.kubernetesProvider = kubernetes.New(c.clients, c.defaultMode, c.meshNamespace, c.tcpStateTable, c.ignored)
 
 	// configurationQueue is used to process configurations from the providers
 	// and deal with pushing them to mesh nodes
@@ -107,7 +108,7 @@ func (c *Controller) Init() error {
 	c.deployer = deployer.New(c.clients, c.configurationQueue, c.meshNamespace)
 
 	// Initialize an empty configuration with a readinesscheck so that configs deployed to nodes mark them as ready.
-	c.traefikConfig = createBaseConfigWithReadiness()
+	c.traefikConfig = base.CreateBaseConfigWithReadiness()
 
 	if c.smiEnabled {
 		c.smiProvider = smi.New(c.clients, c.defaultMode, c.meshNamespace, c.ignored)
@@ -241,17 +242,20 @@ func (c *Controller) processNextMessage() bool {
 	return c.messageQueue.Len() > 0
 }
 
-func (c *Controller) buildConfigurationFromProviders(event message.Message) {
+func (c *Controller) buildConfigurationFromProviders() {
 	// Create all mesh services
 	if err := c.createMeshServices(); err != nil {
 		log.Errorf("could not create mesh services: %v", err)
 	}
 
+	var config *dynamic.Configuration
+	var err error
+
 	if c.smiEnabled {
-		c.smiProvider.BuildConfiguration(event, c.traefikConfig)
-		return
+		config, err = c.smiProvider.BuildConfig()
+	} else {
+		config, err = c.kubernetesProvider.BuildConfig()
 	}
-	config, err := c.kubernetesProvider.BuildConfig()
 	if err != nil {
 		log.Errorf("unable to build configuration: %v", err)
 	}
@@ -282,7 +286,7 @@ func (c *Controller) processCreatedMessage(event message.Message) {
 		return
 	}
 
-	c.buildConfigurationFromProviders(event)
+	c.buildConfigurationFromProviders()
 	c.configurationQueue.Add(message.BuildNewConfigWithVersion(c.traefikConfig))
 }
 
@@ -321,7 +325,7 @@ func (c *Controller) processUpdatedMessage(event message.Message) {
 		return
 	}
 
-	c.buildConfigurationFromProviders(event)
+	c.buildConfigurationFromProviders()
 	c.configurationQueue.Add(message.BuildNewConfigWithVersion(c.traefikConfig))
 }
 
@@ -352,7 +356,7 @@ func (c *Controller) processDeletedMessage(event message.Message) {
 		return
 	}
 
-	c.buildConfigurationFromProviders(event)
+	c.buildConfigurationFromProviders()
 	c.configurationQueue.Add(message.BuildNewConfigWithVersion(c.traefikConfig))
 }
 
@@ -362,11 +366,11 @@ func (c *Controller) createMeshServices() error {
 		return fmt.Errorf("unable to get services: %v", err)
 	}
 
-	log.Debugf("Found Services: %v", services)
 	for _, service := range services {
 		if c.ignored.Ignored(service.Name, service.Namespace) {
 			continue
 		}
+		log.Debugf("Creating mesh for service: %v", service.Name)
 		meshServiceName := c.userServiceToMeshServiceName(service.Name, service.Namespace)
 		for _, subservice := range services {
 			// If there is already a mesh service created, don't bother recreating
@@ -618,36 +622,6 @@ func isMeshPod(pod *corev1.Pod) bool {
 	return pod.Labels["component"] == "maesh-mesh"
 }
 
-func createBaseConfigWithReadiness() *dynamic.Configuration {
-	return &dynamic.Configuration{
-		HTTP: &dynamic.HTTPConfiguration{
-			Routers: map[string]*dynamic.Router{
-				"readiness": {
-					Rule:        "Path(`/ping`)",
-					EntryPoints: []string{"readiness"},
-					Service:     "readiness",
-				},
-			},
-			Services: map[string]*dynamic.Service{
-				"readiness": {
-					LoadBalancer: &dynamic.ServersLoadBalancer{
-						Servers: []dynamic.Server{
-							{
-								URL: "http://127.0.0.1:8080",
-							},
-						},
-					},
-				},
-			},
-			Middlewares: map[string]*dynamic.Middleware{},
-		},
-		TCP: &dynamic.TCPConfiguration{
-			Routers:  map[string]*dynamic.TCPRouter{},
-			Services: map[string]*dynamic.TCPService{},
-		},
-	}
-}
-
 func addBaseSMIMiddlewares(config *dynamic.Configuration) {
 	blockAll := &dynamic.Middleware{
 		IPWhiteList: &dynamic.IPWhiteList{
diff --git a/internal/providers/base/base.go b/internal/providers/base/base.go
new file mode 100644
index 0000000..cc56f2d
--- /dev/null
+++ b/internal/providers/base/base.go
@@ -0,0 +1,60 @@
+package base
+
+import (
+	"github.com/containous/traefik/v2/pkg/config/dynamic"
+	splitv1alpha1 "github.com/deislabs/smi-sdk-go/pkg/apis/split/v1alpha1"
+	corev1 "k8s.io/api/core/v1"
+)
+
+// CreateBaseConfigWithReadiness creates a base configuration for deploying to mesh nodes.
+func CreateBaseConfigWithReadiness() *dynamic.Configuration {
+	return &dynamic.Configuration{
+		HTTP: &dynamic.HTTPConfiguration{
+			Routers: map[string]*dynamic.Router{
+				"readiness": {
+					Rule:        "Path(`/ping`)",
+					EntryPoints: []string{"readiness"},
+					Service:     "readiness",
+				},
+			},
+			Services: map[string]*dynamic.Service{
+				"readiness": {
+					LoadBalancer: &dynamic.ServersLoadBalancer{
+						Servers: []dynamic.Server{
+							{
+								URL: "http://127.0.0.1:8080",
+							},
+						},
+					},
+				},
+			},
+			Middlewares: map[string]*dynamic.Middleware{},
+		},
+		TCP: &dynamic.TCPConfiguration{
+			Routers:  map[string]*dynamic.TCPRouter{},
+			Services: map[string]*dynamic.TCPService{},
+		},
+	}
+}
+
+// GetTrafficSplitFromList returns a trafficsplit from a list.
+func GetTrafficSplitFromList(serviceName string, trafficSplits []*splitv1alpha1.TrafficSplit) *splitv1alpha1.TrafficSplit {
+	for _, t := range trafficSplits {
+		if t.Spec.Service == serviceName {
+			return t
+		}
+	}
+
+	return nil
+}
+
+// GetEndpointsFromList returns an endpoint from a list.
+func GetEndpointsFromList(name, namespace string, endpointList []*corev1.Endpoints) *corev1.Endpoints {
+	for _, endpoints := range endpointList {
+		if endpoints.Name == name && endpoints.Namespace == namespace {
+			return endpoints
+		}
+	}
+
+	return nil
+}
diff --git a/internal/providers/kubernetes/provider.go b/internal/providers/kubernetes/provider.go
index 1647350..e1bb0f4 100644
--- a/internal/providers/kubernetes/provider.go
+++ b/internal/providers/kubernetes/provider.go
@@ -8,6 +8,7 @@ import (
 	"strconv"
 
 	"github.com/containous/maesh/internal/k8s"
+	"github.com/containous/maesh/internal/providers/base"
 	"github.com/containous/traefik/v2/pkg/config/dynamic"
 	log "github.com/sirupsen/logrus"
 	corev1 "k8s.io/api/core/v1"
@@ -20,6 +21,7 @@ type Provider struct {
 	defaultMode   string
 	meshNamespace string
 	tcpStateTable *k8s.State
+	ignored       k8s.IgnoreWrapper
 }
 
 // Init the provider.
@@ -28,12 +30,13 @@ func (p *Provider) Init() {
 }
 
 // New creates a new provider.
-func New(client k8s.CoreV1Client, defaultMode string, meshNamespace string, tcpStateTable *k8s.State) *Provider {
+func New(client k8s.CoreV1Client, defaultMode string, meshNamespace string, tcpStateTable *k8s.State, ignored k8s.IgnoreWrapper) *Provider {
 	p := &Provider{
 		client:        client,
 		defaultMode:   defaultMode,
 		meshNamespace: meshNamespace,
 		tcpStateTable: tcpStateTable,
+		ignored:       ignored,
 	}
 
 	p.Init()
@@ -123,16 +126,19 @@ func (p *Provider) BuildConfig() (*dynamic.Configuration, error) {
 		return nil, fmt.Errorf("unable to get endpoints: %v", err)
 	}
 
-	config := createBaseConfigWithReadiness()
+	config := base.CreateBaseConfigWithReadiness()
 
 	for _, service := range services {
+		if p.ignored.Ignored(service.Name, service.Namespace) {
+			continue
+		}
 		serviceMode := p.getServiceMode(service.Annotations)
 
 		for id, sp := range service.Spec.Ports {
 			key := buildKey(service.Name, service.Namespace, sp.Port)
 
 			if serviceMode == k8s.ServiceTypeHTTP {
-				config.HTTP.Services[key] = p.buildService(getEndpointsFromList(service.Name, service.Namespace, endpoints))
+				config.HTTP.Services[key] = p.buildService(base.GetEndpointsFromList(service.Name, service.Namespace, endpoints))
 				middlewares := p.buildHTTPMiddlewares(service.Annotations)
 				if middlewares != nil {
 					config.HTTP.Routers[key] = p.buildRouter(service.Name, service.Namespace, service.Spec.ClusterIP, 5000+id, key, true)
@@ -145,7 +151,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(getEndpointsFromList(service.Name, service.Namespace, endpoints))
+			config.TCP.Services[key] = p.buildTCPService(base.GetEndpointsFromList(service.Name, service.Namespace, endpoints))
 		}
 	}
 
@@ -210,45 +216,6 @@ func (p *Provider) getMeshPort(serviceName, serviceNamespace string, servicePort
 	return 0
 }
 
-func getEndpointsFromList(name, namespace string, endpointList []*corev1.Endpoints) *corev1.Endpoints {
-	for _, endpoints := range endpointList {
-		if endpoints.Name == name && endpoints.Namespace == namespace {
-			return endpoints
-		}
-	}
-	return nil
-}
-
-func createBaseConfigWithReadiness() *dynamic.Configuration {
-	return &dynamic.Configuration{
-		HTTP: &dynamic.HTTPConfiguration{
-			Routers: map[string]*dynamic.Router{
-				"readiness": {
-					Rule:        "Path(`/ping`)",
-					EntryPoints: []string{"readiness"},
-					Service:     "readiness",
-				},
-			},
-			Services: map[string]*dynamic.Service{
-				"readiness": {
-					LoadBalancer: &dynamic.ServersLoadBalancer{
-						Servers: []dynamic.Server{
-							{
-								URL: "http://127.0.0.1:8080",
-							},
-						},
-					},
-				},
-			},
-			Middlewares: map[string]*dynamic.Middleware{},
-		},
-		TCP: &dynamic.TCPConfiguration{
-			Routers:  map[string]*dynamic.TCPRouter{},
-			Services: map[string]*dynamic.TCPService{},
-		},
-	}
-}
-
 func buildKey(name, namespace string, port int32) string {
 	// Use the hash of the servicename.namespace.port as the key
 	// So that we can update services based on their name
diff --git a/internal/providers/smi/fixtures/build_configuration_http_service.yaml b/internal/providers/smi/fixtures/build_configuration_http_service.yaml
new file mode 100644
index 0000000..66fa854
--- /dev/null
+++ b/internal/providers/smi/fixtures/build_configuration_http_service.yaml
@@ -0,0 +1,70 @@
+---
+apiVersion: specs.smi-spec.io/v1alpha1
+kind: HTTPRouteGroup
+metadata:
+  name: api-service-routes
+matches:
+- name: api
+  pathRegex: /api
+  methods: ["*"]
+- name: metrics
+  pathRegex: /metrics
+  methods: ["GET"]
+
+---
+kind: TrafficTarget
+apiVersion: access.smi-spec.io/v1alpha1
+metadata:
+  name: api-service-metrics
+destination:
+  kind: ServiceAccount
+  name: api-service
+  namespace: default
+specs:
+- kind: HTTPRouteGroup
+  name: api-service-routes
+  matches:
+  - metrics
+sources:
+- kind: ServiceAccount
+  name: prometheus
+  namespace: default
+
+---
+apiVersion: v1
+kind: Endpoints
+metadata:
+  name: demo-service
+subsets:
+- addresses:
+  - ip: 10.1.1.50
+    targetRef:
+      name: example
+      namespace: default
+  ports:
+  - port: 50
+
+---
+apiVersion: v1
+kind: Pod
+metadata:
+  name: example
+spec:
+  serviceAccountName: api-service
+  containers:
+    - name: example
+      image: busybox
+status:
+  podIP: "10.4.3.2"
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: demo-service
+spec:
+  clusterIP: 10.1.0.1
+  ports:
+  - protocol: TCP
+    port: 80
+    name: web
diff --git a/internal/providers/smi/provider.go b/internal/providers/smi/provider.go
index e77beb2..45b14bd 100644
--- a/internal/providers/smi/provider.go
+++ b/internal/providers/smi/provider.go
@@ -9,7 +9,7 @@ import (
 	"strings"
 
 	"github.com/containous/maesh/internal/k8s"
-	"github.com/containous/maesh/internal/message"
+	"github.com/containous/maesh/internal/providers/base"
 	"github.com/containous/traefik/v2/pkg/config/dynamic"
 	accessv1alpha1 "github.com/deislabs/smi-sdk-go/pkg/apis/access/v1alpha1"
 	specsv1alpha1 "github.com/deislabs/smi-sdk-go/pkg/apis/specs/v1alpha1"
@@ -51,181 +51,101 @@ func New(client k8s.Client, defaultMode string, meshNamespace string, ignored k8
 	return p
 }
 
-// BuildConfiguration builds the configuration for routing
+// BuildConfig builds the configuration for routing
 // from a native kubernetes environment.
-func (p *Provider) BuildConfiguration(event message.Message, traefikConfig *dynamic.Configuration) {
-	switch obj := event.Object.(type) {
-	case *corev1.Service:
-		if event.Action == message.TypeCreated {
-			p.buildServiceIntoConfig(obj, nil, traefikConfig)
-		}
-	case *corev1.Endpoints:
-		switch event.Action {
-		case message.TypeCreated:
-			// We don't process created endpoint events, processing is done under service creation.
-		case message.TypeUpdated:
-			p.buildServiceIntoConfig(nil, obj, traefikConfig)
-		case message.TypeDeleted:
-			// We don't precess deleted endpoint events, processing is done under service deletion.
-		}
-	case *accessv1alpha1.TrafficTarget:
-		p.buildAffectedServicesIntoConfig(obj, nil, nil, traefikConfig)
-	case *specsv1alpha1.HTTPRouteGroup:
-		p.buildAffectedServicesIntoConfig(nil, obj, nil, traefikConfig)
-	case *splitv1alpha1.TrafficSplit:
-		p.buildAffectedServicesIntoConfig(nil, nil, obj, traefikConfig)
-	}
-}
-
-func (p *Provider) buildAffectedServicesIntoConfig(trafficTarget *accessv1alpha1.TrafficTarget, httpRouteGroup *specsv1alpha1.HTTPRouteGroup, trafficSplit *splitv1alpha1.TrafficSplit, config *dynamic.Configuration) {
-	namespaces := k8s.Namespaces{}
+func (p *Provider) BuildConfig() (*dynamic.Configuration, error) {
+	config := base.CreateBaseConfigWithReadiness()
 
-	if httpRouteGroup != nil {
-		tts := p.getTrafficTargetsWithHTTPRouteGroup(httpRouteGroup)
-		for _, tt := range tts {
-			if !namespaces.Contains(tt.Destination.Namespace) {
-				namespaces = append(namespaces, tt.Destination.Namespace)
-			}
-		}
+	services, err := p.client.GetServices(metav1.NamespaceAll)
+	if err != nil {
+		return nil, fmt.Errorf("unable to get services: %v", err)
 	}
 
-	if trafficTarget != nil {
-		if !namespaces.Contains(trafficTarget.Destination.Namespace) {
-			namespaces = append(namespaces, trafficTarget.Destination.Namespace)
-		}
+	endpoints, err := p.client.GetEndpointses(metav1.NamespaceAll)
+	if err != nil {
+		return nil, fmt.Errorf("unable to get endpoints: %v", err)
 	}
 
-	if trafficSplit != nil {
-		if !namespaces.Contains(trafficSplit.Namespace) {
-			namespaces = append(namespaces, trafficSplit.Namespace)
-		}
+	trafficTargets, err := p.client.GetTrafficTargets()
+	if err != nil {
+		return nil, fmt.Errorf("unable to get traffictargets: %v", err)
 	}
 
-	for _, namespace := range namespaces {
-		allServices, err := p.client.GetServices(namespace)
-		if err != nil {
-			log.Errorf("Could not get services in namespace %s: %v", namespace, err)
-		}
-
-		for _, service := range allServices {
-			if p.ignored.Ignored(service.Name, service.Namespace) {
-				continue
-			}
-			p.buildServiceIntoConfig(service, nil, config)
-		}
+	trafficSplits, err := p.client.GetTrafficSplits()
+	if err != nil {
+		return nil, fmt.Errorf("unable to get trafficsplits: %v", err)
 	}
-}
 
-func (p *Provider) buildServiceIntoConfig(service *corev1.Service, endpoints *corev1.Endpoints, config *dynamic.Configuration) {
-	var exists bool
-	var err error
-	if service == nil {
-		service, exists, err = p.client.GetService(endpoints.Namespace, endpoints.Name)
-		if err != nil {
-			log.Errorf("Could not get service %s/%s: %v", endpoints.Namespace, endpoints.Name, err)
-			return
-		}
-		if !exists {
-			log.Errorf("service %s/%s does not exist", endpoints.Namespace, endpoints.Name)
-			return
+	for _, service := range services {
+		if p.ignored.Ignored(service.Name, service.Namespace) {
+			continue
 		}
-	}
 
-	if endpoints == nil {
-		endpoints, exists, err = p.client.GetEndpoints(service.Namespace, service.Name)
-		if err != nil {
-			log.Errorf("Could not get endpoints for service %s/%s: %v", service.Namespace, service.Name, err)
-			return
-		}
-		if !exists {
-			log.Errorf("endpoints for service %s/%s do not exist", service.Namespace, service.Name)
-			return
-		}
-	}
+		serviceMode := p.getServiceMode(service.Annotations[k8s.AnnotationServiceType])
+		// Get all traffic targets in the service's namespace.
+		trafficTargetsInNamespace := p.getTrafficTargetsWithDestinationInNamespace(service.Namespace, trafficTargets)
+		log.Debugf("Found traffictargets for service %s/%s: %+v\n", service.Namespace, service.Name, trafficTargets)
+		// Find all traffic targets that are applicable to the service in question.
+		applicableTrafficTargets := p.getApplicableTrafficTargets(base.GetEndpointsFromList(service.Name, service.Namespace, endpoints), trafficTargetsInNamespace)
+		log.Debugf("Found applicable traffictargets for service %s/%s: %+v\n", service.Namespace, service.Name, applicableTrafficTargets)
+		// Group the traffic targets by destination, so that they can be built separately.
+		groupedByDestinationTrafficTargets := p.groupTrafficTargetsByDestination(applicableTrafficTargets)
+		log.Debugf("Found grouped traffictargets for service %s/%s: %+v\n", service.Namespace, service.Name, groupedByDestinationTrafficTargets)
+
+		// Get all traffic split in the service's namespace.
+		trafficSplitsInNamespace := p.getTrafficSplitsWithDestinationInNamespace(service.Namespace, trafficSplits)
+		log.Debugf("Found trafficsplits for service %s/%s: %+v\n", service.Namespace, service.Name, trafficSplitsInNamespace)
+
+		for _, groupedTrafficTargets := range groupedByDestinationTrafficTargets {
+			for _, groupedTrafficTarget := range groupedTrafficTargets {
+				for id, sp := range service.Spec.Ports {
+					key := buildKey(service.Name, service.Namespace, sp.Port, groupedTrafficTarget.Name, groupedTrafficTarget.Namespace)
+
+					//	For each source in the trafficTarget, get a list of IPs to whitelist.
+					var sourceIPs []string
+					for _, source := range groupedTrafficTarget.Sources {
+						fieldSelector := fmt.Sprintf("spec.serviceAccountName=%s", source.Name)
+						// Get all pods with the associated source serviceAccount (can only be in the source namespaces).
+						podList, err := p.client.ListPodWithOptions(source.Namespace, metav1.ListOptions{FieldSelector: fieldSelector})
+						if err != nil {
+							log.Errorf("Could not list pods: %v", err)
+							continue
+						}
 
-	serviceMode := p.getServiceMode(service.Annotations[k8s.AnnotationServiceType])
-	// Get all traffic targets in the service's namespace.
-	trafficTargets := p.getTrafficTargetsWithDestinationInNamespace(service.Namespace)
-	log.Debugf("Found traffictargets for service %s/%s: %+v\n", service.Namespace, service.Name, trafficTargets)
-	// Find all traffic targets that are applicable to the service in question.
-	applicableTrafficTargets := p.getApplicableTrafficTargets(endpoints, trafficTargets)
-	log.Debugf("Found applicable traffictargets for service %s/%s: %+v\n", service.Namespace, service.Name, applicableTrafficTargets)
-	// Group the traffic targets by destination, so that they can be built separately.
-	groupedByDestinationTrafficTargets := p.groupTrafficTargetsByDestination(applicableTrafficTargets)
-	log.Debugf("Found grouped traffictargets for service %s/%s: %+v\n", service.Namespace, service.Name, groupedByDestinationTrafficTargets)
-
-	// Get all traffic split in the service's namespace.
-	trafficSplits := p.getTrafficSplitsWithDestinationInNamespace(service.Namespace)
-	log.Debugf("Found trafficsplits for service %s/%s: %+v\n", service.Namespace, service.Name, trafficSplits)
-
-	for _, groupedTrafficTargets := range groupedByDestinationTrafficTargets {
-		for _, groupedTrafficTarget := range groupedTrafficTargets {
-			for id, sp := range service.Spec.Ports {
-				key := buildKey(service.Name, service.Namespace, sp.Port, groupedTrafficTarget.Name, groupedTrafficTarget.Namespace)
-
-				//	For each source in the trafficTarget, get a list of IPs to whitelist.
-				var sourceIPs []string
-				for _, source := range groupedTrafficTarget.Sources {
-					fieldSelector := fmt.Sprintf("spec.serviceAccountName=%s", source.Name)
-					// Get all pods with the associated source serviceAccount (can only be in the source namespaces).
-					podList, err := p.client.ListPodWithOptions(source.Namespace, metav1.ListOptions{FieldSelector: fieldSelector})
-					if err != nil {
-						log.Errorf("Could not list pods: %v", err)
-						return
+						// Retrieve a list of sourceIPs from the list of pods.
+						for _, pod := range podList.Items {
+							if pod.Status.PodIP != "" {
+								sourceIPs = append(sourceIPs, pod.Status.PodIP)
+							}
+						}
 					}
 
-					// Retrieve a list of sourceIPs from the list of pods.
-					for _, pod := range podList.Items {
-						if pod.Status.PodIP != "" {
-							sourceIPs = append(sourceIPs, pod.Status.PodIP)
+					whitelistKey := groupedTrafficTarget.Name + "-" + groupedTrafficTarget.Namespace + "-" + key + "-whitelist"
+					whitelistMiddleware := k8s.BlockAllMiddlewareKey
+					if serviceMode == k8s.ServiceTypeHTTP {
+						if len(sourceIPs) > 0 {
+							config.HTTP.Middlewares[whitelistKey] = createWhitelistMiddleware(sourceIPs)
+							whitelistMiddleware = whitelistKey
+						}
+						trafficSplit := base.GetTrafficSplitFromList(service.Name, trafficSplitsInNamespace)
+						if trafficSplit == nil {
+							config.HTTP.Routers[key] = p.buildRouterFromTrafficTarget(service.Name, service.Namespace, service.Spec.ClusterIP, groupedTrafficTarget, 5000+id, key, whitelistMiddleware)
+							config.HTTP.Services[key] = p.buildServiceFromTrafficTarget(base.GetEndpointsFromList(service.Name, service.Namespace, endpoints), groupedTrafficTarget)
+							continue
 						}
-					}
-				}
 
-				whitelistKey := groupedTrafficTarget.Name + "-" + groupedTrafficTarget.Namespace + "-" + key + "-whitelist"
-				whitelistMiddleware := k8s.BlockAllMiddlewareKey
-				if serviceMode == k8s.ServiceTypeHTTP {
-					if len(sourceIPs) > 0 {
-						config.HTTP.Middlewares[whitelistKey] = createWhitelistMiddleware(sourceIPs)
-						whitelistMiddleware = whitelistKey
+						p.buildTrafficSplit(config, trafficSplit, sp, id, groupedTrafficTarget, whitelistMiddleware)
 					}
-					trafficSplit := getTrafficSplit(service.Name, trafficSplits)
-					if trafficSplit == nil {
-						config.HTTP.Routers[key] = p.buildRouterFromTrafficTarget(service.Name, service.Namespace, service.Spec.ClusterIP, groupedTrafficTarget, 5000+id, key, whitelistMiddleware)
-						config.HTTP.Services[key] = p.buildServiceFromTrafficTarget(endpoints, groupedTrafficTarget)
-						continue
-					}
-
-					p.buildTrafficSplit(config, trafficSplit, sp, id, groupedTrafficTarget, whitelistMiddleware)
 				}
 			}
 		}
 	}
+	return config, nil
 }
 
-func intToP(v int64) *int {
-	i := int(v)
-	return &i
-}
-
-func getTrafficSplit(serviceName string, trafficSplits []*splitv1alpha1.TrafficSplit) *splitv1alpha1.TrafficSplit {
-	for _, t := range trafficSplits {
-		if t.Spec.Service == serviceName {
-			return t
-		}
-	}
-
-	return nil
-}
-
-func (p *Provider) getTrafficTargetsWithDestinationInNamespace(namespace string) []*accessv1alpha1.TrafficTarget {
+func (p *Provider) getTrafficTargetsWithDestinationInNamespace(namespace string, trafficTargets []*accessv1alpha1.TrafficTarget) []*accessv1alpha1.TrafficTarget {
 	var result []*accessv1alpha1.TrafficTarget
-	allTrafficTargets, err := p.client.GetTrafficTargets()
-	if err != nil {
-		log.Error("Could not get a list of all TrafficTargets")
-	}
-
-	for _, trafficTarget := range allTrafficTargets {
+	for _, trafficTarget := range trafficTargets {
 		if trafficTarget.Destination.Namespace == namespace {
 			result = append(result, trafficTarget)
 		}
@@ -238,16 +158,11 @@ func (p *Provider) getTrafficTargetsWithDestinationInNamespace(namespace string)
 	return result
 }
 
-func (p *Provider) getTrafficSplitsWithDestinationInNamespace(namespace string) []*splitv1alpha1.TrafficSplit {
+func (p *Provider) getTrafficSplitsWithDestinationInNamespace(namespace string, trafficSplits []*splitv1alpha1.TrafficSplit) []*splitv1alpha1.TrafficSplit {
 	var result []*splitv1alpha1.TrafficSplit
-	allTrafficSplit, err := p.client.GetTrafficSplits()
-	if err != nil {
-		log.Error("Could not get a list of all TrafficTargets")
-	}
-
-	for _, trafficTarget := range allTrafficSplit {
-		if trafficTarget.Namespace == namespace {
-			result = append(result, trafficTarget)
+	for _, trafficSplit := range trafficSplits {
+		if trafficSplit.Namespace == namespace {
+			result = append(result, trafficSplit)
 		}
 	}
 
@@ -258,27 +173,6 @@ func (p *Provider) getTrafficSplitsWithDestinationInNamespace(namespace string)
 	return result
 }
 
-func (p *Provider) getTrafficTargetsWithHTTPRouteGroup(httpRouteGroup *specsv1alpha1.HTTPRouteGroup) []*accessv1alpha1.TrafficTarget {
-	var result []*accessv1alpha1.TrafficTarget
-	allTrafficTargets, err := p.client.GetTrafficTargets()
-	if err != nil {
-		log.Error("Could not get a list of all TrafficTargets")
-	}
-
-	for _, trafficTarget := range allTrafficTargets {
-		for _, spec := range trafficTarget.Specs {
-			if spec.Kind == "HTTPRouteGroup" && spec.Name == httpRouteGroup.Name {
-				result = append(result, trafficTarget)
-			}
-		}
-	}
-
-	if len(result) == 0 {
-		log.Debugf("No TrafficTargets with HTTPRouteGroup: %s", httpRouteGroup.Name)
-	}
-	return result
-}
-
 func (p *Provider) getApplicableTrafficTargets(endpoints *corev1.Endpoints, trafficTargets []*accessv1alpha1.TrafficTarget) []*accessv1alpha1.TrafficTarget {
 	var result []*accessv1alpha1.TrafficTarget
 	if len(endpoints.Subsets) == 0 {
@@ -325,7 +219,7 @@ func (p *Provider) getApplicableTrafficTargets(endpoints *corev1.Endpoints, traf
 			}
 
 			if !validPodFound {
-				// No valid pods with serviceAccound found on the subset, so it is not affected
+				// No valid pods with serviceAccount found on the subset, so it is not affected
 				log.Debugf("Endpoints %s/%s has no valid pods with destination service account: %s", endpoints.Namespace, endpoints.Name, trafficTarget.Destination.Name)
 				continue
 			}
@@ -531,3 +425,8 @@ func createWhitelistMiddleware(sourceIPs []string) *dynamic.Middleware {
 		},
 	}
 }
+
+func intToP(v int64) *int {
+	i := int(v)
+	return &i
+}


Test patch:
diff --git a/internal/providers/base/base_test.go b/internal/providers/base/base_test.go
new file mode 100644
index 0000000..289a06a
--- /dev/null
+++ b/internal/providers/base/base_test.go
@@ -0,0 +1,82 @@
+package base
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestGetEndpointsFromList(t *testing.T) {
+	testCases := []struct {
+		desc      string
+		provided  []*corev1.Endpoints
+		name      string
+		namespace string
+		expected  *corev1.Endpoints
+	}{
+		{
+			desc:      "empty list",
+			provided:  []*corev1.Endpoints{},
+			name:      "foo",
+			namespace: "bar",
+			expected:  nil,
+		},
+		{
+			desc: "match in list",
+			provided: []*corev1.Endpoints{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "foo",
+						Namespace: "bar",
+					},
+				},
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "fifi",
+						Namespace: "fufu",
+					},
+				},
+			},
+			name:      "foo",
+			namespace: "bar",
+			expected: &corev1.Endpoints{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "foo",
+					Namespace: "bar",
+				},
+			},
+		},
+		{
+			desc: "no match in list",
+			provided: []*corev1.Endpoints{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "bar",
+						Namespace: "bar",
+					},
+				},
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "fifi",
+						Namespace: "fufu",
+					},
+				},
+			},
+			name:      "foo",
+			namespace: "bar",
+			expected:  nil,
+		},
+	}
+
+	for _, test := range testCases {
+		test := test
+		t.Run(test.desc, func(t *testing.T) {
+			t.Parallel()
+
+			actual := GetEndpointsFromList(test.name, test.namespace, test.provided)
+			assert.Equal(t, test.expected, actual)
+		})
+	}
+}
diff --git a/internal/providers/kubernetes/provider_test.go b/internal/providers/kubernetes/provider_test.go
index 43cb5eb..225feaa 100644
--- a/internal/providers/kubernetes/provider_test.go
+++ b/internal/providers/kubernetes/provider_test.go
@@ -26,7 +26,7 @@ func TestBuildRouter(t *testing.T) {
 		Service:     "bar",
 	}
 
-	provider := New(nil, k8s.ServiceTypeHTTP, meshNamespace, nil)
+	provider := New(nil, k8s.ServiceTypeHTTP, meshNamespace, nil, k8s.NewIgnored(meshNamespace, []string{}))
 
 	name := "test"
 	namespace := "foo"
@@ -47,7 +47,7 @@ func TestBuildTCPRouter(t *testing.T) {
 		Service:     "bar",
 	}
 
-	provider := New(nil, k8s.ServiceTypeTCP, meshNamespace, nil)
+	provider := New(nil, k8s.ServiceTypeTCP, meshNamespace, nil, k8s.NewIgnored(meshNamespace, []string{}))
 
 	port := 10000
 	associatedService := "bar"
@@ -273,7 +273,7 @@ func TestBuildConfiguration(t *testing.T) {
 				clientMock.EnableServiceError()
 			}
 
-			provider := New(clientMock, k8s.ServiceTypeHTTP, meshNamespace, stateTable)
+			provider := New(clientMock, k8s.ServiceTypeHTTP, meshNamespace, stateTable, k8s.NewIgnored(meshNamespace, []string{}))
 			config, err := provider.BuildConfig()
 			assert.Equal(t, test.expected, config)
 			if test.endpointsError || test.serviceError {
@@ -338,7 +338,7 @@ func TestBuildService(t *testing.T) {
 			t.Parallel()
 
 			clientMock := k8s.NewCoreV1ClientMock(test.mockFile)
-			provider := New(clientMock, k8s.ServiceTypeHTTP, meshNamespace, nil)
+			provider := New(clientMock, k8s.ServiceTypeHTTP, meshNamespace, nil, k8s.NewIgnored(meshNamespace, []string{}))
 			actual := provider.buildService(test.endpoints)
 			assert.Equal(t, test.expected, actual)
 		})
@@ -409,7 +409,7 @@ func TestBuildTCPService(t *testing.T) {
 			t.Parallel()
 
 			clientMock := k8s.NewCoreV1ClientMock(test.mockFile)
-			provider := New(clientMock, k8s.ServiceTypeHTTP, meshNamespace, stateTable)
+			provider := New(clientMock, k8s.ServiceTypeHTTP, meshNamespace, stateTable, k8s.NewIgnored(meshNamespace, []string{}))
 			actual := provider.buildTCPService(test.endpoints)
 			assert.Equal(t, test.expected, actual)
 		})
@@ -455,7 +455,7 @@ func TestGetMeshPort(t *testing.T) {
 		t.Run(test.desc, func(t *testing.T) {
 			t.Parallel()
 
-			provider := New(nil, k8s.ServiceTypeHTTP, meshNamespace, stateTable)
+			provider := New(nil, k8s.ServiceTypeHTTP, meshNamespace, stateTable, k8s.NewIgnored(meshNamespace, []string{}))
 			actual := provider.getMeshPort(test.name, test.namespace, test.port)
 			assert.Equal(t, test.expected, actual)
 		})
@@ -516,82 +516,9 @@ func TestBuildHTTPMiddlewares(t *testing.T) {
 		t.Run(test.desc, func(t *testing.T) {
 			t.Parallel()
 
-			provider := New(nil, k8s.ServiceTypeHTTP, meshNamespace, nil)
+			provider := New(nil, k8s.ServiceTypeHTTP, meshNamespace, nil, k8s.NewIgnored(meshNamespace, []string{}))
 			actual := provider.buildHTTPMiddlewares(test.annotations)
 			assert.Equal(t, test.expected, actual)
 		})
 	}
 }
-
-func TestGetEndpointsFromList(t *testing.T) {
-	testCases := []struct {
-		desc      string
-		provided  []*corev1.Endpoints
-		name      string
-		namespace string
-		expected  *corev1.Endpoints
-	}{
-		{
-			desc:      "empty list",
-			provided:  []*corev1.Endpoints{},
-			name:      "foo",
-			namespace: "bar",
-			expected:  nil,
-		},
-		{
-			desc: "match in list",
-			provided: []*corev1.Endpoints{
-				{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "foo",
-						Namespace: "bar",
-					},
-				},
-				{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "fifi",
-						Namespace: "fufu",
-					},
-				},
-			},
-			name:      "foo",
-			namespace: "bar",
-			expected: &corev1.Endpoints{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "foo",
-					Namespace: "bar",
-				},
-			},
-		},
-		{
-			desc: "no match in list",
-			provided: []*corev1.Endpoints{
-				{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "bar",
-						Namespace: "bar",
-					},
-				},
-				{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "fifi",
-						Namespace: "fufu",
-					},
-				},
-			},
-			name:      "foo",
-			namespace: "bar",
-			expected:  nil,
-		},
-	}
-
-	for _, test := range testCases {
-		test := test
-		t.Run(test.desc, func(t *testing.T) {
-			t.Parallel()
-
-			actual := getEndpointsFromList(test.name, test.namespace, test.provided)
-			assert.Equal(t, test.expected, actual)
-		})
-	}
-}
diff --git a/internal/providers/smi/provider_test.go b/internal/providers/smi/provider_test.go
index d9c27b4..fe44b52 100644
--- a/internal/providers/smi/provider_test.go
+++ b/internal/providers/smi/provider_test.go
@@ -4,7 +4,6 @@ import (
 	"testing"
 
 	"github.com/containous/maesh/internal/k8s"
-	"github.com/containous/maesh/internal/message"
 	"github.com/containous/traefik/v2/pkg/config/dynamic"
 	accessv1alpha1 "github.com/deislabs/smi-sdk-go/pkg/apis/access/v1alpha1"
 	specsv1alpha1 "github.com/deislabs/smi-sdk-go/pkg/apis/specs/v1alpha1"
@@ -133,14 +132,10 @@ func TestGetTrafficTargetsWithDestinationInNamespace(t *testing.T) {
 			},
 		},
 	}
-	actual := provider.getTrafficTargetsWithDestinationInNamespace("foo")
+	allTrafficTargets, err := clientMock.GetTrafficTargets()
+	assert.NoError(t, err)
+	actual := provider.getTrafficTargetsWithDestinationInNamespace("foo", allTrafficTargets)
 	assert.Equal(t, expected, actual)
-
-	clientMock.EnableTrafficTargetError()
-
-	var newExpected []*accessv1alpha1.TrafficTarget
-	newActual := provider.getTrafficTargetsWithDestinationInNamespace("foo")
-	assert.Equal(t, newExpected, newActual)
 }
 
 func TestBuildRouterFromTrafficTarget(t *testing.T) {
@@ -1219,39 +1214,14 @@ func TestGroupTrafficTargetsByDestination(t *testing.T) {
 func TestBuildConfiguration(t *testing.T) {
 	testCases := []struct {
 		desc           string
-		event          message.Message
-		provided       *dynamic.Configuration
+		mockFile       string
 		expected       *dynamic.Configuration
 		endpointsError bool
 		serviceError   bool
 	}{
 		{
-			desc: "simple configuration build with empty event",
-			expected: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			provided: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-		},
-		{
-			desc: "simple configuration build with HTTP service event",
+			desc:     "simple configuration build with HTTP service",
+			mockFile: "build_configuration_http_service.yaml",
 			expected: &dynamic.Configuration{
 				HTTP: &dynamic.HTTPConfiguration{
 					Routers: map[string]*dynamic.Router{
@@ -1261,6 +1231,11 @@ func TestBuildConfiguration(t *testing.T) {
 							Service:     "demo-servi-default-80-api-servic-default-5bb66e727779b5ba",
 							Middlewares: []string{"api-service-metrics-default-demo-servi-default-80-api-servic-default-5bb66e727779b5ba-whitelist"},
 						},
+						"readiness": {
+							EntryPoints: []string{"readiness"},
+							Service:     "readiness",
+							Rule:        "Path(`/ping`)",
+						},
 					},
 					Services: map[string]*dynamic.Service{
 						"demo-servi-default-80-api-servic-default-5bb66e727779b5ba": {
@@ -1273,77 +1248,21 @@ func TestBuildConfiguration(t *testing.T) {
 								},
 							},
 						},
-					},
-					Middlewares: map[string]*dynamic.Middleware{
-						"api-service-metrics-default-demo-servi-default-80-api-servic-default-5bb66e727779b5ba-whitelist": {
-							IPWhiteList: &dynamic.IPWhiteList{
-								SourceRange: []string{"10.4.3.2"},
-							},
-						},
-					},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			provided: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			event: message.Message{
-				Object: &corev1.Service{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "demo-service",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: corev1.ServiceSpec{
-						ClusterIP: "10.1.0.1",
-						Ports: []corev1.ServicePort{
-							{
-								Name:     "test",
-								Port:     80,
-								Protocol: "TCP",
-							},
-						},
-					},
-				},
-				Action: message.TypeCreated,
-			},
-		},
-		{
-			desc: "simple configuration build with HTTP endpoint event",
-			expected: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers: map[string]*dynamic.Router{
-						"demo-test-default-80-api-servic-default-7f2af3b9b8c32573": {
-							EntryPoints: []string{"http-5000"},
-							Rule:        "(PathPrefix(`/metrics`) && Method(`GET`) && (Host(`demo-test.default.maesh`) || Host(`10.1.0.1`)))",
-							Service:     "demo-test-default-80-api-servic-default-7f2af3b9b8c32573",
-							Middlewares: []string{"api-service-metrics-default-demo-test-default-80-api-servic-default-7f2af3b9b8c32573-whitelist"},
-						},
-					},
-					Services: map[string]*dynamic.Service{
-						"demo-test-default-80-api-servic-default-7f2af3b9b8c32573": {
+						"readiness": {
 							LoadBalancer: &dynamic.ServersLoadBalancer{
-								PassHostHeader: true,
+								PassHostHeader: false,
 								Servers: []dynamic.Server{
 									{
-										URL: "http://10.1.1.50:50",
+										URL:    "http://127.0.0.1:8080",
+										Scheme: "",
+										Port:   "",
 									},
 								},
 							},
 						},
 					},
 					Middlewares: map[string]*dynamic.Middleware{
-						"api-service-metrics-default-demo-test-default-80-api-servic-default-7f2af3b9b8c32573-whitelist": {
+						"api-service-metrics-default-demo-servi-default-80-api-servic-default-5bb66e727779b5ba-whitelist": {
 							IPWhiteList: &dynamic.IPWhiteList{
 								SourceRange: []string{"10.4.3.2"},
 							},
@@ -1355,246 +1274,26 @@ func TestBuildConfiguration(t *testing.T) {
 					Services: map[string]*dynamic.TCPService{},
 				},
 			},
-			provided: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			event: message.Message{
-				Object: &corev1.Endpoints{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "demo-test",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Subsets: []corev1.EndpointSubset{
-						{
-							Addresses: []corev1.EndpointAddress{
-								{
-									IP: "10.1.1.50",
-									TargetRef: &corev1.ObjectReference{
-										Name:      "example",
-										Namespace: metav1.NamespaceDefault,
-									},
-								},
-							},
-							Ports: []corev1.EndpointPort{
-								{
-									Port: 50,
-								},
-							},
-						},
-					},
-				},
-				Action: message.TypeUpdated,
-			},
 		},
 		{
-			desc: "simple configuration build with endpoint error",
-			expected: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			provided: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			event: message.Message{
-				Object: &corev1.Service{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "demo-service",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: corev1.ServiceSpec{
-						ClusterIP: "10.1.0.1",
-						Ports: []corev1.ServicePort{
-							{
-								Name:     "test",
-								Port:     80,
-								Protocol: "TCP",
-							},
-						},
-					},
-				},
-				Action: message.TypeCreated,
-			},
+			desc:           "simple configuration build with endpoint error",
+			mockFile:       "build_configuration_http_service.yaml",
+			expected:       nil,
 			endpointsError: true,
 		},
 		{
-			desc: "simple configuration build with endpoints don't exist",
-			expected: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			provided: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			event: message.Message{
-				Object: &corev1.Service{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "demo-service-foobar",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: corev1.ServiceSpec{
-						ClusterIP: "10.1.0.1",
-						Ports: []corev1.ServicePort{
-							{
-								Name:     "test",
-								Port:     80,
-								Protocol: "TCP",
-							},
-						},
-					},
-				},
-				Action: message.TypeCreated,
-			},
-		},
-		{
-			desc: "simple configuration build with service error",
-			expected: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			provided: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			event: message.Message{
-				Object: &corev1.Endpoints{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "demo-test",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Subsets: []corev1.EndpointSubset{
-						{
-							Addresses: []corev1.EndpointAddress{
-								{
-									IP: "10.1.1.50",
-									TargetRef: &corev1.ObjectReference{
-										Name:      "example",
-										Namespace: metav1.NamespaceDefault,
-									},
-								},
-							},
-							Ports: []corev1.EndpointPort{
-								{
-									Port: 50,
-								},
-							},
-						},
-					},
-				},
-				Action: message.TypeUpdated,
-			},
+			desc:         "simple configuration build with service error",
+			mockFile:     "build_configuration_http_service.yaml",
+			expected:     nil,
 			serviceError: true,
 		},
-		{
-			desc: "simple configuration build with service doesn't exist",
-			expected: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			provided: &dynamic.Configuration{
-				HTTP: &dynamic.HTTPConfiguration{
-					Routers:     map[string]*dynamic.Router{},
-					Services:    map[string]*dynamic.Service{},
-					Middlewares: map[string]*dynamic.Middleware{},
-				},
-				TCP: &dynamic.TCPConfiguration{
-					Routers:  map[string]*dynamic.TCPRouter{},
-					Services: map[string]*dynamic.TCPService{},
-				},
-			},
-			event: message.Message{
-				Object: &corev1.Endpoints{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "demo-test-foobar",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Subsets: []corev1.EndpointSubset{
-						{
-							Addresses: []corev1.EndpointAddress{
-								{
-									IP: "10.1.1.50",
-									TargetRef: &corev1.ObjectReference{
-										Name:      "example",
-										Namespace: metav1.NamespaceDefault,
-									},
-								},
-							},
-							Ports: []corev1.EndpointPort{
-								{
-									Port: 50,
-								},
-							},
-						},
-					},
-				},
-				Action: message.TypeUpdated,
-			},
-		},
 	}
 
 	for _, test := range testCases {
 		test := test
 		t.Run(test.desc, func(t *testing.T) {
 			t.Parallel()
-			clientMock := k8s.NewClientMock("mock.yaml")
+			clientMock := k8s.NewClientMock(test.mockFile)
 			if test.endpointsError {
 				clientMock.EnableEndpointsError()
 			}
@@ -1603,8 +1302,11 @@ func TestBuildConfiguration(t *testing.T) {
 			}
 
 			provider := New(clientMock, k8s.ServiceTypeHTTP, meshNamespace, k8s.NewIgnored(meshNamespace, []string{}))
-			provider.BuildConfiguration(test.event, test.provided)
-			assert.Equal(t, test.expected, test.provided)
+			config, err := provider.BuildConfig()
+			assert.Equal(t, test.expected, config)
+			if test.endpointsError || test.serviceError {
+				assert.Error(t, err)
+			}
 		})
 	}
 }