You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by ri...@apache.org on 2023/11/24 14:04:05 UTC

(incubator-kie-kogito-serverless-operator) branch main updated: kie-issues-308: Operator driven service discovery API Phase2 (#309)

This is an automated email from the ASF dual-hosted git repository.

ricardozanini pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-kogito-serverless-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new 162f3693 kie-issues-308: Operator driven service discovery API Phase2 (#309)
162f3693 is described below

commit 162f3693844de04e94b447b29253eb3ed38057ad
Author: Walter Medvedeo <wm...@gmail.com>
AuthorDate: Fri Nov 24 15:03:59 2023 +0100

    kie-issues-308: Operator driven service discovery API Phase2 (#309)
    
    * kie-issues-308: Operator driven service discovery API Phase2
        - Add the discovery of kubernetes Deployment, StatefulSet, and Ingress objects to the service discovery API.
    
    * kie-issues-308: Operator driven service discovery API Phase2
        - Code review suggestions 1, simplify the Deployment and StatefulSet discovery
---
 controllers/discovery/discovery.go                 |  93 +++++---
 controllers/discovery/discovery_test.go            | 218 +++++++++++++++---
 controllers/discovery/knative_catalog.go           |  31 +--
 controllers/discovery/kubernetes_catalog.go        | 116 +++++++---
 controllers/discovery/kubernetes_constants.go      |  29 +++
 controllers/discovery/port_utils.go                |  57 +++--
 controllers/discovery/port_utils_test.go           |  77 ++++---
 controllers/discovery/queries.go                   | 110 +++++++---
 controllers/discovery/queries_test.go              | 244 +++++++++++++--------
 controllers/discovery/test_utils.go                | 157 ++++++++++---
 controllers/discovery/uri_parser.go                |  42 ++--
 controllers/discovery/uri_parser_test.go           |  54 +++--
 controllers/discovery/uri_utils.go                 |  41 ++--
 controllers/discovery/uri_utils_test.go            |  83 +++----
 controllers/profiles/common/app_properties.go      |  31 +--
 controllers/profiles/common/app_properties_test.go |  31 +--
 16 files changed, 965 insertions(+), 449 deletions(-)

diff --git a/controllers/discovery/discovery.go b/controllers/discovery/discovery.go
index 06c4709f..4b170b9f 100644
--- a/controllers/discovery/discovery.go
+++ b/controllers/discovery/discovery.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -27,8 +32,9 @@ const (
 	KubernetesScheme = "kubernetes"
 	OpenshiftScheme  = "openshift"
 
-	// PortLabel well known label name to select a particular target port
-	PortLabel = "port"
+	// PortQueryParam well known query param to select a particular target port, for example when a service is being
+	// discovered and there are many ports to select.
+	PortQueryParam = "port"
 
 	// KubernetesDNSAddress use this output format with kubernetes services and pods to resolve to the corresponding
 	// kubernetes DNS name. see: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
@@ -53,11 +59,11 @@ const (
 )
 
 type ResourceUri struct {
-	Scheme       string
-	GVK          v1.GroupVersionKind
-	Namespace    string
-	Name         string
-	CustomLabels map[string]string
+	Scheme      string
+	GVK         v1.GroupVersionKind
+	Namespace   string
+	Name        string
+	QueryParams map[string]string
 }
 
 // ServiceCatalog is the entry point to resolve resource addresses given a ResourceUri.
@@ -105,9 +111,9 @@ type ResourceUriBuilder struct {
 func NewResourceUriBuilder(scheme string) ResourceUriBuilder {
 	return ResourceUriBuilder{
 		uri: &ResourceUri{
-			Scheme:       scheme,
-			GVK:          v1.GroupVersionKind{},
-			CustomLabels: map[string]string{},
+			Scheme:      scheme,
+			GVK:         v1.GroupVersionKind{},
+			QueryParams: map[string]string{},
 		},
 	}
 }
@@ -137,13 +143,13 @@ func (b ResourceUriBuilder) Name(name string) ResourceUriBuilder {
 	return b
 }
 
-func (b ResourceUriBuilder) Port(customPort string) ResourceUriBuilder {
+func (b ResourceUriBuilder) WithPort(customPort string) ResourceUriBuilder {
 	b.uri.SetPort(customPort)
 	return b
 }
 
-func (b ResourceUriBuilder) WithLabel(labelName string, labelValue string) ResourceUriBuilder {
-	b.uri.CustomLabels[labelName] = labelValue
+func (b ResourceUriBuilder) WithQueryParam(param string, value string) ResourceUriBuilder {
+	b.uri.AddQueryParam(param, value)
 	return b
 }
 
@@ -151,26 +157,43 @@ func (b ResourceUriBuilder) Build() *ResourceUri {
 	return b.uri
 }
 
-func (r *ResourceUri) AddLabel(name string, value string) *ResourceUri {
+func (r *ResourceUri) AddQueryParam(name string, value string) {
 	if len(value) > 0 {
-		r.CustomLabels[name] = value
+		r.QueryParams[name] = value
 	}
-	return r
 }
 
-func (r *ResourceUri) GetLabel(name string) string {
+func (r *ResourceUri) GetQueryParam(name string) string {
 	if len(name) > 0 {
-		return r.CustomLabels[name]
+		return r.QueryParams[name]
 	}
 	return ""
 }
 
-func (r *ResourceUri) SetPort(value string) *ResourceUri {
-	return r.AddLabel(PortLabel, value)
+func (r *ResourceUri) SetPort(value string) {
+	r.AddQueryParam(PortQueryParam, value)
 }
 
 func (r *ResourceUri) GetPort() string {
-	return r.GetLabel(PortLabel)
+	return r.GetQueryParam(PortQueryParam)
+}
+
+// GetCustomLabels returns all the query parameters that not considered well known query parameters, and thus, has no
+// particular semantic during the discovery. These arbitrary parameters are normally considered as labels, and when
+// present, and the service discovery must give a preference over a set of resources, they can be used to do a filtering.
+// by labels.
+func (r *ResourceUri) GetCustomLabels() map[string]string {
+	customQueryParams := make(map[string]string)
+	for k, v := range r.QueryParams {
+		if !isWellKnownQueryParam(k) && len(v) > 0 {
+			customQueryParams[k] = v
+		}
+	}
+	return customQueryParams
+}
+
+func isWellKnownQueryParam(k string) bool {
+	return k == PortQueryParam
 }
 
 func (r *ResourceUri) String() string {
@@ -184,7 +207,7 @@ func (r *ResourceUri) String() string {
 	uri = appendWithDelimiter(uri, r.Namespace, "/")
 	uri = appendWithDelimiter(uri, r.Name, "/")
 
-	return appendWithDelimiter(uri, buildLabelsString(r.CustomLabels, "&"), "?")
+	return appendWithDelimiter(uri, buildLabelsString(r.QueryParams, "&"), "?")
 }
 
 func appendWithDelimiter(value string, toAppend string, delimiter string) string {
diff --git a/controllers/discovery/discovery_test.go b/controllers/discovery/discovery_test.go
index e54b4685..e03fcb01 100644
--- a/controllers/discovery/discovery_test.go
+++ b/controllers/discovery/discovery_test.go
@@ -1,25 +1,32 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
 import (
 	"context"
+	"fmt"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 	corev1 "k8s.io/api/core/v1"
+	v1 "k8s.io/api/networking/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 )
 
@@ -29,22 +36,24 @@ func Test_NewResourceUriBuilder(t *testing.T) {
 		Group("apps").
 		Version("v1").
 		Namespace(namespace1).
-		Name(service1).
-		Port("custom-port").
-		WithLabel(label1, valueLabel1).Build()
+		Name(service1Name).
+		WithPort("custom-port-value").
+		WithQueryParam(label1, valueLabel1).Build()
 
 	assert.Equal(t, "deployments", resourceUri.GVK.Kind)
 	assert.Equal(t, "apps", resourceUri.GVK.Group)
 	assert.Equal(t, "v1", resourceUri.GVK.Version)
 	assert.Equal(t, namespace1, resourceUri.Namespace)
-	assert.Equal(t, service1, resourceUri.Name)
-	assert.Equal(t, 2, len(resourceUri.CustomLabels))
-	assert.Equal(t, "custom-port", resourceUri.CustomLabels["port"])
-	assert.Equal(t, valueLabel1, resourceUri.CustomLabels[label1])
+	assert.Equal(t, service1Name, resourceUri.Name)
+	assert.Equal(t, 2, len(resourceUri.QueryParams))
+	assert.Equal(t, "custom-port-value", resourceUri.GetPort())
+	assert.Equal(t, valueLabel1, resourceUri.QueryParams[label1])
+	assert.Equal(t, 1, len(resourceUri.GetCustomLabels()))
+	assert.Equal(t, valueLabel1, resourceUri.GetCustomLabels()[label1])
 }
 
 func Test_QueryKubernetesServiceDNSMode(t *testing.T) {
-	doTestQueryKubernetesService(t, KubernetesDNSAddress, "http://service1.namespace1.svc:80")
+	doTestQueryKubernetesService(t, KubernetesDNSAddress, "http://service1Name.namespace1.svc:80")
 }
 
 func Test_QueryKubernetesServiceIPAddressMode(t *testing.T) {
@@ -52,7 +61,7 @@ func Test_QueryKubernetesServiceIPAddressMode(t *testing.T) {
 }
 
 func doTestQueryKubernetesService(t *testing.T, outputFormat string, expectedUri string) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort(httpProtocolName, tcp, defaultHttp))
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort(httpProtocol, tcp, defaultHttpPort))
 	service.Spec.Type = corev1.ServiceTypeNodePort
 	service.Spec.ClusterIP = "10.1.5.18"
 	cli := fake.NewClientBuilder().WithRuntimeObjects(service).Build()
@@ -61,7 +70,7 @@ func doTestQueryKubernetesService(t *testing.T, outputFormat string, expectedUri
 		Kind("services").
 		Version("v1").
 		Namespace(namespace1).
-		Name(service1).Build(), outputFormat, expectedUri)
+		Name(service1Name).Build(), outputFormat, expectedUri)
 }
 
 func Test_QueryKubernetesPodDNSMode(t *testing.T) {
@@ -73,8 +82,8 @@ func Test_QueryKubernetesPodIPAddressMode(t *testing.T) {
 }
 
 func doTestQueryKubernetesPod(t *testing.T, outputFormat string, expectedUri string) {
-	pod := mockPodWithContainers(namespace1, pod1,
-		*mockContainerWithPorts("container1", mockContainerPort(httpProtocolName, tcp, defaultHttp)))
+	pod := mockPodWithContainers(namespace1, pod1Name,
+		*mockContainerWithPorts("container1Name", mockContainerPort(httpProtocol, tcp, defaultHttpPort)))
 	pod.Status.PodIP = "10.1.12.13"
 	cli := fake.NewClientBuilder().WithRuntimeObjects(pod).Build()
 	ctg := NewServiceCatalog(cli)
@@ -82,7 +91,159 @@ func doTestQueryKubernetesPod(t *testing.T, outputFormat string, expectedUri str
 		Kind("pods").
 		Version("v1").
 		Namespace(namespace1).
-		Name(pod1).Build(), outputFormat, expectedUri)
+		Name(pod1Name).Build(), outputFormat, expectedUri)
+}
+
+func Test_QueryKubernetesDeploymentWithServiceDNSMode(t *testing.T) {
+	doTesQueryKubernetesDeploymentWithService(t, KubernetesDNSAddress, "http://service1Name.namespace1.svc:80")
+}
+
+func Test_QueryKubernetesDeploymentWithServiceIPAddressMode(t *testing.T) {
+	doTesQueryKubernetesDeploymentWithService(t, KubernetesIPAddress, "http://10.1.15.16:80")
+}
+
+func doTesQueryKubernetesDeploymentWithService(t *testing.T, outputFormat string, expectedUri string) {
+	selector := map[string]string{
+		label1: valueLabel1,
+		label2: valueLabel2,
+	}
+
+	deployment := mockDeployment(namespace1, deployment1Name, nil, &selector)
+
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort(httpProtocol, tcp, defaultHttpPort))
+	service.Spec.Selector = selector
+	service.Spec.ClusterIP = "10.1.15.16"
+	service.Spec.Type = corev1.ServiceTypeNodePort
+
+	cli := fake.NewClientBuilder().WithRuntimeObjects(deployment, service).Build()
+	ctg := NewServiceCatalog(cli)
+
+	doTestQuery(t, ctg, *NewResourceUriBuilder(KubernetesScheme).
+		Group("apps").
+		Version("v1").
+		Kind("deployments").
+		Namespace(namespace1).
+		Name(deployment1Name).Build(),
+		outputFormat, expectedUri)
+}
+
+func Test_QueryKubernetesDeploymentWithoutServiceDNSMode(t *testing.T) {
+	doTestQueryKubernetesDeploymentWithoutService(t, KubernetesDNSAddress)
+}
+
+func Test_QueryKubernetesDeploymentWithoutServiceIPAddressMode(t *testing.T) {
+	doTestQueryKubernetesDeploymentWithoutService(t, KubernetesIPAddress)
+}
+
+func doTestQueryKubernetesDeploymentWithoutService(t *testing.T, outputFormat string) {
+	selector := map[string]string{
+		label1: valueLabel1,
+		label2: valueLabel2,
+	}
+
+	deployment := mockDeployment(namespace1, deployment1Name, nil, &selector)
+	ctg := NewServiceCatalog(fake.NewClientBuilder().WithRuntimeObjects(deployment).Build())
+
+	uri := *NewResourceUriBuilder(KubernetesScheme).
+		Group("apps").
+		Version("v1").
+		Kind("deployments").
+		Namespace(namespace1).
+		Name(deployment1Name).Build()
+
+	doTestQueryWithError(t, ctg, uri, outputFormat, fmt.Sprintf("no service was found for the deployment: %s", uri.Name))
+}
+
+func Test_QueryKubernetesStatefulSetWithServiceDNSMode(t *testing.T) {
+	doTestQueryKubernetesStatefulSetWithService(t, KubernetesDNSAddress, "http://service1Name.namespace1.svc:80")
+}
+
+func Test_QueryKubernetesStatefulSetWithServiceIPAddressMode(t *testing.T) {
+	doTestQueryKubernetesStatefulSetWithService(t, KubernetesIPAddress, "http://10.1.18.19:80")
+}
+
+func doTestQueryKubernetesStatefulSetWithService(t *testing.T, outputFormat string, expectedUri string) {
+	selector := map[string]string{
+		label1: valueLabel1,
+		label2: valueLabel2,
+	}
+
+	statefulSet := mockStatefulSet(namespace1, statefulSet1Name, nil, &selector)
+
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort(httpProtocol, tcp, defaultHttpPort))
+	service.Spec.Selector = selector
+	service.Spec.ClusterIP = "10.1.18.19"
+	service.Spec.Type = corev1.ServiceTypeNodePort
+
+	cli := fake.NewClientBuilder().WithRuntimeObjects(statefulSet, service).Build()
+	ctg := NewServiceCatalog(cli)
+
+	doTestQuery(t, ctg, *NewResourceUriBuilder(KubernetesScheme).
+		Group("apps").
+		Version("v1").
+		Kind("statefulsets").
+		Namespace(namespace1).
+		Name(statefulSet1Name).Build(),
+		outputFormat, expectedUri)
+}
+
+func Test_QueryKubernetesStatefulSetWithoutServiceDNSMode(t *testing.T) {
+	doTestQueryKubernetesStatefulSetWithoutService(t, KubernetesDNSAddress)
+}
+
+func Test_QueryKubernetesStatefulSetWithoutServiceIPAddressMode(t *testing.T) {
+	doTestQueryKubernetesStatefulSetWithoutService(t, KubernetesIPAddress)
+}
+
+func doTestQueryKubernetesStatefulSetWithoutService(t *testing.T, outputFormat string) {
+	selector := map[string]string{
+		label1: valueLabel1,
+		label2: valueLabel2,
+	}
+
+	statefulSet := mockStatefulSet(namespace1, statefulSet1Name, nil, &selector)
+	ctg := NewServiceCatalog(fake.NewClientBuilder().WithRuntimeObjects(statefulSet).Build())
+
+	uri := *NewResourceUriBuilder(KubernetesScheme).
+		Group("apps").
+		Version("v1").
+		Kind("statefulsets").
+		Namespace(namespace1).
+		Name(statefulSet1Name).Build()
+	doTestQueryWithError(t, ctg, uri, outputFormat, fmt.Sprintf("no service was found for the statefulset: %s", uri.Name))
+}
+
+func Test_QueryKubernetesIngressHostNoTLS(t *testing.T) {
+	doTestQueryKubernetesIngress(t, "myingresshost.com.uy", "", false, KubernetesIPAddress, "http://myingresshost.com.uy:80")
+}
+
+func Test_QueryKubernetesIngressHostWithTLS(t *testing.T) {
+	doTestQueryKubernetesIngress(t, "myingresshost.com.uy", "", true, KubernetesIPAddress, "https://myingresshost.com.uy:443")
+}
+
+func Test_QueryKubernetesIngressIPNoTLS(t *testing.T) {
+	doTestQueryKubernetesIngress(t, "", "142.250.184.174", false, KubernetesIPAddress, "http://142.250.184.174:80")
+}
+
+func Test_QueryKubernetesIngressIPWithTLS(t *testing.T) {
+	doTestQueryKubernetesIngress(t, "", "142.250.184.174", true, KubernetesIPAddress, "https://142.250.184.174:443")
+}
+
+func doTestQueryKubernetesIngress(t *testing.T, hostName string, ip string, tls bool, outputFormat string, expectedUri string) {
+	ingress := mockIngress(namespace1, ingress1Name)
+
+	ingress.Status.LoadBalancer.Ingress = []v1.IngressLoadBalancerIngress{{Hostname: hostName, IP: ip}}
+	if tls {
+		ingress.Spec.TLS = []v1.IngressTLS{{}}
+	}
+	cli := fake.NewClientBuilder().WithRuntimeObjects(ingress).Build()
+	ctg := NewServiceCatalog(cli)
+	doTestQuery(t, ctg, *NewResourceUriBuilder(KubernetesScheme).
+		Kind("ingresses").
+		Group("networking.k8s.io").
+		Version("v1").
+		Namespace(namespace1).
+		Name(ingress1Name).Build(), outputFormat, expectedUri)
 }
 
 func doTestQuery(t *testing.T, ctg ServiceCatalog, resourceUri ResourceUri, outputFormat, expectedUri string) {
@@ -90,3 +251,8 @@ func doTestQuery(t *testing.T, ctg ServiceCatalog, resourceUri ResourceUri, outp
 	assert.NoError(t, err)
 	assert.Equal(t, expectedUri, uri)
 }
+
+func doTestQueryWithError(t *testing.T, ctg ServiceCatalog, resourceUri ResourceUri, outputFormat string, expectedErrorMessage string) {
+	_, err := ctg.Query(context.TODO(), resourceUri, outputFormat)
+	assert.ErrorContains(t, err, expectedErrorMessage)
+}
diff --git a/controllers/discovery/knative_catalog.go b/controllers/discovery/knative_catalog.go
index ad7fb011..77760015 100644
--- a/controllers/discovery/knative_catalog.go
+++ b/controllers/discovery/knative_catalog.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
diff --git a/controllers/discovery/kubernetes_catalog.go b/controllers/discovery/kubernetes_catalog.go
index eb526e75..324a798e 100644
--- a/controllers/discovery/kubernetes_catalog.go
+++ b/controllers/discovery/kubernetes_catalog.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -22,8 +27,11 @@ import (
 )
 
 const (
-	serviceKind = "services"
-	podKind     = "pods"
+	serviceKind     = "services"
+	podKind         = "pods"
+	deploymentKind  = "deployments"
+	statefulSetKind = "statefulsets"
+	ingressKind     = "ingresses"
 )
 
 type k8sServiceCatalog struct {
@@ -42,8 +50,14 @@ func (c k8sServiceCatalog) Query(ctx context.Context, uri ResourceUri, outputFor
 		return c.resolveServiceQuery(ctx, uri, outputFormat)
 	case podKind:
 		return c.resolvePodQuery(ctx, uri, outputFormat)
+	case deploymentKind:
+		return c.resolveDeploymentQuery(ctx, uri, outputFormat)
+	case statefulSetKind:
+		return c.resolveStatefulSetQuery(ctx, uri, outputFormat)
+	case ingressKind:
+		return c.resolveIngressQuery(ctx, uri)
 	default:
-		return "", fmt.Errorf("resolution of kind: %s is not yet implemented", uri.GVK.Kind)
+		return "", fmt.Errorf("resolution of kind: %s is not implemented", uri.GVK.Kind)
 	}
 }
 
@@ -58,21 +72,67 @@ func (c k8sServiceCatalog) resolveServiceQuery(ctx context.Context, uri Resource
 }
 
 func (c k8sServiceCatalog) resolvePodQuery(ctx context.Context, uri ResourceUri, outputFormat string) (string, error) {
-	if pod, service, err := findPodAndReferenceServiceByPodLabels(ctx, c.Client, uri.Namespace, uri.Name); err != nil {
+	if pod, serviceList, err := findPodAndReferenceServices(ctx, c.Client, uri.Namespace, uri.Name); err != nil {
 		return "", err
 	} else {
-		if service != nil {
-			if serviceUri, err := resolveServiceUri(service, uri.GetPort(), outputFormat); err != nil {
-				return "", err
-			} else {
-				return serviceUri, nil
-			}
+		if serviceList != nil && len(serviceList.Items) > 0 {
+			referenceService := selectBestSuitedServiceByCustomLabels(serviceList, uri.GetCustomLabels())
+			return resolveServiceUri(referenceService, uri.GetPort(), outputFormat)
 		} else {
-			if podUri, err := resolvePodUri(pod, "", uri.GetPort(), outputFormat); err != nil {
-				return "", err
-			} else {
-				return podUri, nil
-			}
+			return resolvePodUri(pod, "", uri.GetPort(), outputFormat)
 		}
 	}
 }
+
+func (c k8sServiceCatalog) resolveDeploymentQuery(ctx context.Context, uri ResourceUri, outputFormat string) (string, error) {
+	if deployment, err := findDeployment(ctx, c.Client, uri.Namespace, uri.Name); err != nil {
+		return "", err
+	} else {
+		if serviceList, err := findServicesBySelectorTarget(ctx, c.Client, uri.Namespace, deployment.Spec.Selector.MatchLabels); err != nil {
+			return "", err
+		} else if len(serviceList.Items) == 0 {
+			return "", fmt.Errorf("no service was found for the deployment: %s in namespace: %s", uri.Name, uri.Namespace)
+		} else {
+			referenceService := selectBestSuitedServiceByCustomLabels(serviceList, uri.GetCustomLabels())
+			return resolveServiceUri(referenceService, uri.GetPort(), outputFormat)
+		}
+	}
+}
+
+func (c k8sServiceCatalog) resolveStatefulSetQuery(ctx context.Context, uri ResourceUri, outputFormat string) (string, error) {
+	if statefulSet, err := findStatefulSet(ctx, c.Client, uri.Namespace, uri.Name); err != nil {
+		return "", err
+	} else {
+		if serviceList, err := findServicesBySelectorTarget(ctx, c.Client, uri.Namespace, statefulSet.Spec.Selector.MatchLabels); err != nil {
+			return "", err
+		} else if len(serviceList.Items) == 0 {
+			return "", fmt.Errorf("no service was found for the statefulset: %s in namespace: %s", uri.Name, uri.Namespace)
+		} else {
+			referenceService := selectBestSuitedServiceByCustomLabels(serviceList, uri.GetCustomLabels())
+			return resolveServiceUri(referenceService, uri.GetPort(), outputFormat)
+		}
+	}
+}
+
+func (c k8sServiceCatalog) resolveIngressQuery(ctx context.Context, uri ResourceUri) (string, error) {
+	if ingress, err := findIngress(ctx, c.Client, uri.Namespace, uri.Name); err != nil {
+		return "", err
+	} else {
+		// for now stick with the first ip or hostname.
+		loadBalancer := ingress.Status.LoadBalancer.Ingress[0]
+		var scheme = httpProtocol
+		var host string
+		var port = defaultHttpPort
+		if len(loadBalancer.Hostname) > 0 {
+			host = loadBalancer.Hostname
+		} else {
+			host = loadBalancer.IP
+		}
+		// An Ingress does not expose arbitrary ports or protocols other than HTTP and HTTPS
+		if len(ingress.Spec.TLS) >= 1 {
+			scheme = httpsProtocol
+			port = defaultHttpsPort
+		}
+		return buildURI(scheme, host, port), nil
+	}
+}
diff --git a/controllers/discovery/kubernetes_constants.go b/controllers/discovery/kubernetes_constants.go
new file mode 100644
index 00000000..78d472d1
--- /dev/null
+++ b/controllers/discovery/kubernetes_constants.go
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package discovery
+
+const (
+	httpProtocol         = "http"
+	httpsProtocol        = "https"
+	webProtocol          = "web"
+	defaultHttpPort      = 80
+	defaultHttpsPort     = 443
+	defaultAppSecurePort = 8443
+)
diff --git a/controllers/discovery/port_utils.go b/controllers/discovery/port_utils.go
index 891995c6..207d7c6b 100644
--- a/controllers/discovery/port_utils.go
+++ b/controllers/discovery/port_utils.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -19,16 +24,8 @@ import (
 	corev1 "k8s.io/api/core/v1"
 )
 
-const (
-	httpProtocolName  = "http"
-	httpsProtocolName = "https"
-	webProtocolName   = "web"
-	securePort        = 443
-	appSecurePort     = 8443
-)
-
 func isSecurePort(port int) bool {
-	return port == securePort || port == appSecurePort
+	return port == defaultHttpsPort || port == defaultAppSecurePort
 }
 
 // findBestSuitedServicePort returns the best suited ServicePort to connect to a service.
@@ -42,15 +39,15 @@ func findBestSuitedServicePort(service *corev1.Service, customPort string) *core
 		}
 	}
 	// has ssl port?
-	if result, _ := kubernetes.GetServicePortByName(httpsProtocolName, service); result != nil {
+	if result, _ := kubernetes.GetServicePortByName(httpsProtocol, service); result != nil {
 		return result
 	}
 	// has http port?
-	if result, _ := kubernetes.GetServicePortByName(httpProtocolName, service); result != nil {
+	if result, _ := kubernetes.GetServicePortByName(httpProtocol, service); result != nil {
 		return result
 	}
 	// has web port?
-	if result, _ := kubernetes.GetServicePortByName(webProtocolName, service); result != nil {
+	if result, _ := kubernetes.GetServicePortByName(webProtocol, service); result != nil {
 		return result
 	}
 	// by definition a service must always have at least one port, get the first port.
@@ -58,7 +55,7 @@ func findBestSuitedServicePort(service *corev1.Service, customPort string) *core
 }
 
 func isSecureServicePort(servicePort *corev1.ServicePort) bool {
-	return servicePort.Name == httpsProtocolName || isSecurePort(int(servicePort.Port))
+	return servicePort.Name == httpsProtocol || isSecurePort(int(servicePort.Port))
 }
 
 // findBestSuitedContainerPort returns the best suited PortPort to connect to a pod, or nil if the pod has no ports at all.
@@ -76,15 +73,15 @@ func findBestSuitedContainerPort(container *corev1.Container, customPort string)
 		}
 	}
 	// has ssl port?
-	if result, _ := kubernetes.GetContainerPortByName(httpsProtocolName, container); result != nil {
+	if result, _ := kubernetes.GetContainerPortByName(httpsProtocol, container); result != nil {
 		return result
 	}
 	// has http port?
-	if result, _ := kubernetes.GetContainerPortByName(httpProtocolName, container); result != nil {
+	if result, _ := kubernetes.GetContainerPortByName(httpProtocol, container); result != nil {
 		return result
 	}
 	// has web port?
-	if result, _ := kubernetes.GetContainerPortByName(webProtocolName, container); result != nil {
+	if result, _ := kubernetes.GetContainerPortByName(webProtocol, container); result != nil {
 		return result
 	}
 	// when defined, a ContainerPort must always have containerPort (Required value)
@@ -92,5 +89,5 @@ func findBestSuitedContainerPort(container *corev1.Container, customPort string)
 }
 
 func isSecureContainerPort(containerPort *corev1.ContainerPort) bool {
-	return containerPort.Name == httpsProtocolName || isSecurePort(int(containerPort.ContainerPort))
+	return containerPort.Name == httpsProtocol || isSecurePort(int(containerPort.ContainerPort))
 }
diff --git a/controllers/discovery/port_utils_test.go b/controllers/discovery/port_utils_test.go
index 367dc428..9e01b9bc 100644
--- a/controllers/discovery/port_utils_test.go
+++ b/controllers/discovery/port_utils_test.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -29,44 +34,44 @@ func TestIsSecurePort(t *testing.T) {
 }
 
 func TestBestSuitedServicePort_BestIsCustomPort(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort("not-wanted", tcp, 8282),
-		mockServicePort(httpsProtocolName, tcp, defaultHttps),
-		mockServicePort(customPortName, tcp, defaultHttp))
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort("not-wanted", tcp, 8282),
+		mockServicePort(httpsProtocol, tcp, defaultHttpsPort),
+		mockServicePort(customPortName, tcp, defaultHttpPort))
 	doTestBestSuitedServicePort(t, service, customPortName, &service.Spec.Ports[2])
 }
 
 func TestBestSuitedServicePort_BestIsHttpsPort(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort("not-wanted", tcp, 8282),
-		mockServicePort(httpProtocolName, tcp, defaultHttp),
-		mockServicePort(httpsProtocolName, tcp, defaultHttps))
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort("not-wanted", tcp, 8282),
+		mockServicePort(httpProtocol, tcp, defaultHttpPort),
+		mockServicePort(httpsProtocol, tcp, defaultHttpsPort))
 	doTestBestSuitedServicePort(t, service, "", &service.Spec.Ports[2])
 }
 
 func TestBestSuitedServicePort_BestIsHttpPort(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort("not-wanted", tcp, 8282),
-		mockServicePort(webProtocolName, tcp, 81),
-		mockServicePort(httpProtocolName, tcp, defaultHttp))
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort("not-wanted", tcp, 8282),
+		mockServicePort(webProtocol, tcp, 81),
+		mockServicePort(httpProtocol, tcp, defaultHttpPort))
 	doTestBestSuitedServicePort(t, service, "", &service.Spec.Ports[2])
 }
 
 func TestBestSuitedServicePort_BestWebPort(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort("not-wanted", tcp, 8282),
-		mockServicePort(webProtocolName, tcp, 81))
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort("not-wanted", tcp, 8282),
+		mockServicePort(webProtocol, tcp, 81))
 	doTestBestSuitedServicePort(t, service, "", &service.Spec.Ports[1])
 }
 
 func TestBestSuitedServicePort_BestIsFirst(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort("first-port", tcp, 8282),
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort("first-port", tcp, 8282),
 		mockServicePort("second-port", tcp, 8383))
 	doTestBestSuitedServicePort(t, service, "", &service.Spec.Ports[0])
 }
 
 func TestIsSecureServicePort(t *testing.T) {
-	servicePort := mockServicePort(httpsProtocolName, tcp, 443)
+	servicePort := mockServicePort(httpsProtocol, tcp, 443)
 	assert.True(t, isSecureServicePort(&servicePort))
 	servicePort = mockServicePort("other-secure-port", tcp, 443)
 	assert.True(t, isSecureServicePort(&servicePort))
-	servicePort = mockServicePort(httpProtocolName, tcp, 80)
+	servicePort = mockServicePort(httpProtocol, tcp, 80)
 	assert.False(t, isSecureServicePort(&servicePort))
 }
 
@@ -81,28 +86,28 @@ func TestBestSuitedContainerPort_ContainerWithNoPorts(t *testing.T) {
 
 func TestBestSuitedContainerPort_BestIsCustomPort(t *testing.T) {
 	container := mockContainerWithPorts("", mockContainerPort("not-wanted", tcp, 8282),
-		mockContainerPort(httpsProtocolName, tcp, defaultHttps),
-		mockContainerPort(customPortName, tcp, defaultHttp))
+		mockContainerPort(httpsProtocol, tcp, defaultHttpsPort),
+		mockContainerPort(customPortName, tcp, defaultHttpPort))
 	doTestBestSuitedContainerPort(t, container, customPortName, &container.Ports[2])
 }
 
 func TestBestSuitedContainerPort_BestIsHttpsPort(t *testing.T) {
 	container := mockContainerWithPorts("", mockContainerPort("not-wanted", tcp, 8282),
-		mockContainerPort(httpProtocolName, tcp, defaultHttp),
-		mockContainerPort(httpsProtocolName, tcp, defaultHttps))
+		mockContainerPort(httpProtocol, tcp, defaultHttpPort),
+		mockContainerPort(httpsProtocol, tcp, defaultHttpsPort))
 	doTestBestSuitedContainerPort(t, container, "", &container.Ports[2])
 }
 
 func TestBestSuitedContainerPort_BestIsHttpPort(t *testing.T) {
 	container := mockContainerWithPorts("", mockContainerPort("not-wanted", tcp, 8282),
-		mockContainerPort(webProtocolName, tcp, 81),
-		mockContainerPort(httpProtocolName, tcp, defaultHttp))
+		mockContainerPort(webProtocol, tcp, 81),
+		mockContainerPort(httpProtocol, tcp, defaultHttpsPort))
 	doTestBestSuitedContainerPort(t, container, "", &container.Ports[2])
 }
 
 func TestBestSuitedContainerPort_BestWebPort(t *testing.T) {
 	container := mockContainerWithPorts("", mockContainerPort("not-wanted", tcp, 8282),
-		mockContainerPort(webProtocolName, tcp, 81))
+		mockContainerPort(webProtocol, tcp, 81))
 	doTestBestSuitedContainerPort(t, container, "", &container.Ports[1])
 }
 
@@ -118,10 +123,10 @@ func doTestBestSuitedContainerPort(t *testing.T, container *corev1.Container, cu
 }
 
 func TestIsSecureContainerPort(t *testing.T) {
-	containerPort := mockContainerPort(httpsProtocolName, tcp, 443)
+	containerPort := mockContainerPort(httpsProtocol, tcp, 443)
 	assert.True(t, isSecureContainerPort(&containerPort))
 	containerPort = mockContainerPort("other-secure-port", tcp, 443)
 	assert.True(t, isSecureContainerPort(&containerPort))
-	containerPort = mockContainerPort(httpProtocolName, tcp, 80)
+	containerPort = mockContainerPort(httpProtocol, tcp, 80)
 	assert.False(t, isSecureContainerPort(&containerPort))
 }
diff --git a/controllers/discovery/queries.go b/controllers/discovery/queries.go
index 5710201d..37a7e1a6 100644
--- a/controllers/discovery/queries.go
+++ b/controllers/discovery/queries.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -24,8 +29,6 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-const podTemplateHashLabel = "pod-template-hash"
-
 // findService finds a service by name in the given namespace.
 func findService(ctx context.Context, cli client.Client, namespace string, name string) (*corev1.Service, error) {
 	service := &corev1.Service{}
@@ -35,13 +38,65 @@ func findService(ctx context.Context, cli client.Client, namespace string, name
 	return service, nil
 }
 
-// findServiceByLabels finds a service by a set of matching labels in the given namespace.
-func findServiceByLabels(ctx context.Context, cli client.Client, namespace string, labels map[string]string) (*corev1.ServiceList, error) {
+// findServicesBySelectorTarget finds the services for which all the configured selector labels are present in the
+// selection target map.
+func findServicesBySelectorTarget(ctx context.Context, cli client.Client, namespace string, selectorTarget map[string]string) (*corev1.ServiceList, error) {
 	serviceList := &corev1.ServiceList{}
-	if err := cli.List(ctx, serviceList, client.InNamespace(namespace), client.MatchingLabels(labels)); err != nil {
+	items := make([]corev1.Service, 0)
+	if err := cli.List(ctx, serviceList, client.InNamespace(namespace)); err != nil {
 		return nil, err
+	} else {
+		for _, service := range serviceList.Items {
+			if len(service.Spec.Selector) > 0 && containsSubset(selectorTarget, service.Spec.Selector) {
+				items = append(items, service)
+			}
+		}
+	}
+	return &corev1.ServiceList{Items: items}, nil
+}
+
+// selectBestSuitedServiceByCustomLabels In situations where a previous query returned many Services, for example, to
+// access a set of pods, or a deployment, we can filter them by a set of customLabels, to determine which one is the best suited.
+func selectBestSuitedServiceByCustomLabels(serviceList *corev1.ServiceList, customLabels map[string]string) *corev1.Service {
+	var filteredService *corev1.Service = nil
+	if len(serviceList.Items) > 0 {
+		if len(serviceList.Items) == 1 {
+			filteredService = &serviceList.Items[0]
+		} else {
+			filteredService = &serviceList.Items[0]
+			if len(customLabels) > 0 {
+				if filteredServiceList := filterServiceListByLabelsSubset(serviceList, customLabels); len(filteredServiceList.Items) > 0 {
+					filteredService = &filteredServiceList.Items[0]
+				}
+			}
+		}
+	}
+	return filteredService
+}
+
+func filterServiceListByLabelsSubset(serviceList *corev1.ServiceList, labels map[string]string) *corev1.ServiceList {
+	var items = make([]corev1.Service, 0)
+	for _, service := range serviceList.Items {
+		if containsSubset(service.Labels, labels) {
+			items = append(items, service)
+		}
+	}
+	return &corev1.ServiceList{Items: items}
+}
+
+func containsSubset(container map[string]string, subset map[string]string) bool {
+	if container == nil {
+		return subset == nil
+	} else if subset == nil {
+		return true
+	} else {
+		for k, v := range subset {
+			if cv := container[k]; cv != v {
+				return false
+			}
+		}
 	}
-	return serviceList, nil
+	return true
 }
 
 // findPod finds a pod by name in the given namespace.
@@ -53,21 +108,18 @@ func findPod(ctx context.Context, cli client.Client, namespace string, name stri
 	return pod, nil
 }
 
-// findPodAndReferenceServiceByPodLabels finds a pod by name in the given namespace at the same time it piggybacks it's
-// reference service if any. The reference service is determined by using the same set of labels as the pod.
-func findPodAndReferenceServiceByPodLabels(ctx context.Context, cli client.Client, namespace string, name string) (*corev1.Pod, *corev1.Service, error) {
+// findPodAndReferenceServices finds a pod by name in the given namespace, at the same time it piggybacks potential
+// reference services if any. The reference services are determined by looking if the corresponding selector labels
+// matches the pod labels.
+func findPodAndReferenceServices(ctx context.Context, cli client.Client, namespace string, name string) (*corev1.Pod, *corev1.ServiceList, error) {
 	if pod, err := findPod(ctx, cli, namespace, name); err != nil {
 		return nil, nil, err
 	} else {
-		queryLabels := pod.Labels
-		// pod-template-hash is pod dependent, mustn't be considered.
-		delete(queryLabels, podTemplateHashLabel)
-		if len(queryLabels) > 0 {
-			// check if we have a defined reference service
-			if serviceList, err := findServiceByLabels(ctx, cli, namespace, queryLabels); err != nil {
+		if len(pod.Labels) > 0 {
+			if serviceList, err := findServicesBySelectorTarget(ctx, cli, namespace, pod.Labels); err != nil {
 				return nil, nil, err
 			} else if len(serviceList.Items) > 0 {
-				return pod, &serviceList.Items[0], nil
+				return pod, serviceList, nil
 			}
 		}
 		return pod, nil, nil
diff --git a/controllers/discovery/queries_test.go b/controllers/discovery/queries_test.go
index 4c130407..b0500b78 100644
--- a/controllers/discovery/queries_test.go
+++ b/controllers/discovery/queries_test.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -22,14 +27,13 @@ import (
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	networkingV1 "k8s.io/api/networking/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 )
 
 func Test_findService(t *testing.T) {
 	service := mockService1(nil)
 	cli := fake.NewClientBuilder().WithRuntimeObjects(service).Build()
-	result, err := findService(context.TODO(), cli, namespace1, service1)
+	result, err := findService(context.TODO(), cli, namespace1, service1Name)
 
 	assert.NoError(t, err)
 	assert.Equal(t, service, result)
@@ -37,45 +41,108 @@ func Test_findService(t *testing.T) {
 
 func Test_findServiceNotFound(t *testing.T) {
 	cli := fake.NewClientBuilder().Build()
-	_, err := findService(context.TODO(), cli, namespace1, service1)
-	assert.ErrorContains(t, err, "\"service1\" not found")
+	_, err := findService(context.TODO(), cli, namespace1, service1Name)
+	assert.ErrorContains(t, err, "\"service1Name\" not found")
 }
 
-func Test_findServiceByLabels(t *testing.T) {
-	labels := &map[string]string{
+func Test_findServicesBySelectorTarget(t *testing.T) {
+	selector1Labels := &map[string]string{
+		label1: valueLabel1,
+		label2: valueLabel2,
+	}
+	selector2Labels := &map[string]string{
+		label1: valueLabel1,
+		label3: valueLabel3,
+	}
+	selector3Labels := &map[string]string{
 		label1: valueLabel1,
 		label2: valueLabel2,
 	}
-	service := mockService1(labels)
-	cli := fake.NewClientBuilder().WithRuntimeObjects(service).Build()
-	serviceList, err := findServiceByLabels(context.TODO(), cli, namespace1, *labels)
+
+	service1 := mockService1(selector1Labels)
+	service2 := mockService2(selector2Labels)
+	service3 := mockService3(selector3Labels)
+	cli := fake.NewClientBuilder().WithRuntimeObjects(service1, service2, service3).Build()
+	serviceList, err := findServicesBySelectorTarget(context.TODO(), cli, namespace1, *selector1Labels)
 
 	assert.NoError(t, err)
-	assert.Len(t, serviceList.Items, 1)
-	assert.Equal(t, service, &serviceList.Items[0])
+	assert.Len(t, serviceList.Items, 2)
+	assert.Equal(t, service1, &serviceList.Items[0])
+	assert.Equal(t, service3, &serviceList.Items[1])
 }
 
-func Test_findServiceByLabelsNotFound(t *testing.T) {
-	labels := &map[string]string{
+func Test_findServicesBySelectorTargetNotFound(t *testing.T) {
+	selectorLabels := &map[string]string{
 		label1: valueLabel1,
 		label2: valueLabel2,
 	}
 	queryLabels := map[string]string{
 		label1: valueLabel1,
 	}
-	service := mockService1(labels)
+	service := mockService1(selectorLabels)
 	cli := fake.NewClientBuilder().WithRuntimeObjects(service).Build()
-	serviceList, err := findServiceByLabels(context.TODO(), cli, namespace1, queryLabels)
+	serviceList, err := findServicesBySelectorTarget(context.TODO(), cli, namespace1, queryLabels)
 
 	assert.NoError(t, err)
-	assert.Len(t, serviceList.Items, 1)
-	assert.Equal(t, service, &serviceList.Items[0])
+	assert.Len(t, serviceList.Items, 0)
+}
+
+func Test_selectBestSuitedServiceByCustomLabels(t *testing.T) {
+	service1 := mockService1(nil)
+	service1.Labels = map[string]string{
+		label1: valueLabel1,
+		label2: valueLabel2,
+	}
+	service2 := mockService2(nil)
+	service2.Labels = map[string]string{
+		label1:        valueLabel1,
+		label3:        valueLabel3,
+		"environment": "dev",
+	}
+	service3 := mockService2(nil)
+	service3.Labels = map[string]string{
+		label2: valueLabel2,
+		label3: valueLabel3,
+	}
+	serviceList := &corev1.ServiceList{
+		Items: []corev1.Service{*service1, *service2, *service3},
+	}
+	bestSuitedService := selectBestSuitedServiceByCustomLabels(serviceList, map[string]string{"environment": "dev"})
+	assert.Equal(t, service2, bestSuitedService)
+}
+
+func Test_filterServiceListByLabelsSubset(t *testing.T) {
+	service1 := mockService1(nil)
+	service1.Labels = map[string]string{
+		label1: valueLabel1,
+	}
+	service2 := mockService2(nil)
+	service2.Labels = map[string]string{
+		label1: valueLabel1,
+		label3: valueLabel3,
+	}
+	service3 := mockService3(nil)
+	service3.Labels = map[string]string{
+		label1: valueLabel1,
+		label2: valueLabel2,
+		label3: valueLabel3,
+	}
+	serviceList := &corev1.ServiceList{
+		Items: []corev1.Service{*service1, *service2, *service3},
+	}
+	filteredServiceList := filterServiceListByLabelsSubset(serviceList, map[string]string{
+		label1: valueLabel1,
+		label3: valueLabel3})
+
+	assert.Len(t, filteredServiceList.Items, 2)
+	assert.Equal(t, *service2, filteredServiceList.Items[0])
+	assert.Equal(t, *service3, filteredServiceList.Items[1])
 }
 
 func Test_findPod(t *testing.T) {
 	pod := mockPod1(nil)
 	cli := fake.NewClientBuilder().WithRuntimeObjects(pod).Build()
-	result, err := findPod(context.TODO(), cli, namespace1, pod1)
+	result, err := findPod(context.TODO(), cli, namespace1, pod1Name)
 
 	assert.NoError(t, err)
 	assert.Equal(t, pod, result)
@@ -83,45 +150,51 @@ func Test_findPod(t *testing.T) {
 
 func Test_findPodNotFound(t *testing.T) {
 	cli := fake.NewClientBuilder().Build()
-	_, err := findPod(context.TODO(), cli, namespace1, pod1)
-	assert.ErrorContains(t, err, "\"pod1\" not found")
+	_, err := findPod(context.TODO(), cli, namespace1, pod1Name)
+	assert.ErrorContains(t, err, "\"pod1Name\" not found")
 }
 
-func Test_findPodAndReferenceServiceByPodLabelsWithReferenceService(t *testing.T) {
+func Test_findPodAndReferenceServicesWithReferenceService(t *testing.T) {
 	podLabels := &map[string]string{
 		label1: valueLabel1,
 		label2: valueLabel2,
+		label3: valueLabel3,
 	}
-	service := mockService1(podLabels)
+	selectorLabels := &map[string]string{
+		label1: valueLabel1,
+		label2: valueLabel2,
+	}
+	service := mockService1(selectorLabels)
 	pod := mockPod1(podLabels)
 	cli := fake.NewClientBuilder().WithRuntimeObjects(service, pod).Build()
-	resultPod, resultService, err := findPodAndReferenceServiceByPodLabels(context.TODO(), cli, namespace1, pod1)
+	resultPod, referenceServices, err := findPodAndReferenceServices(context.TODO(), cli, namespace1, pod1Name)
 	assert.NoError(t, err)
 	assert.Equal(t, pod, resultPod)
-	assert.Equal(t, service, resultService)
+	assert.Len(t, referenceServices.Items, 1)
+	assert.Equal(t, *service, referenceServices.Items[0])
 }
 
-func Test_findPodAndReferenceServiceByPodLabelsWithoutReferenceService(t *testing.T) {
+func Test_findPodAndReferenceServicesWithoutReferenceService(t *testing.T) {
 	podLabels := &map[string]string{
 		label1: valueLabel1,
-		label2: valueLabel2,
 	}
-	serviceLabels := &map[string]string{
+	selectorLabels := &map[string]string{
 		label1: valueLabel1,
+		label2: valueLabel2,
 	}
-	service := mockService1(serviceLabels)
+	service := mockService1(selectorLabels)
 	pod := mockPod1(podLabels)
 	cli := fake.NewClientBuilder().WithRuntimeObjects(service, pod).Build()
-	resultPod, resultService, err := findPodAndReferenceServiceByPodLabels(context.TODO(), cli, namespace1, pod1)
+	resultPod, referenceServices, err := findPodAndReferenceServices(context.TODO(), cli, namespace1, pod1Name)
 	assert.NoError(t, err)
 	assert.Equal(t, pod, resultPod)
-	assert.Nil(t, resultService)
+	assert.Nil(t, referenceServices)
 }
 
-func Test_findPodAndReferenceServiceByPodLabelsNotFound(t *testing.T) {
+func Test_findPodAndReferenceServicesNotFound(t *testing.T) {
 	cli := fake.NewClientBuilder().Build()
-	resultPod, resultService, err := findPodAndReferenceServiceByPodLabels(context.TODO(), cli, namespace1, pod1)
-	assert.ErrorContains(t, err, "\"pod1\" not found")
+	resultPod, resultService, err := findPodAndReferenceServices(context.TODO(), cli, namespace1, pod1Name)
+	assert.ErrorContains(t, err, "\"pod1Name\" not found")
 	assert.Nil(t, resultPod)
 	assert.Nil(t, resultService)
 }
@@ -129,7 +202,7 @@ func Test_findPodAndReferenceServiceByPodLabelsNotFound(t *testing.T) {
 func Test_findDeployment(t *testing.T) {
 	deployment := mockDeployment1(nil)
 	cli := fake.NewClientBuilder().WithRuntimeObjects(deployment).Build()
-	result, err := findDeployment(context.TODO(), cli, namespace1, deployment1)
+	result, err := findDeployment(context.TODO(), cli, namespace1, deployment1Name)
 
 	assert.NoError(t, err)
 	assert.Equal(t, deployment, result)
@@ -137,14 +210,14 @@ func Test_findDeployment(t *testing.T) {
 
 func Test_findDeploymentNotFound(t *testing.T) {
 	cli := fake.NewClientBuilder().Build()
-	_, err := findDeployment(context.TODO(), cli, namespace1, deployment1)
-	assert.ErrorContains(t, err, "\"deployment1\" not found")
+	_, err := findDeployment(context.TODO(), cli, namespace1, deployment1Name)
+	assert.ErrorContains(t, err, "\"deployment1Name\" not found")
 }
 
 func Test_findStatefulSet(t *testing.T) {
 	statefulSet := mockStatefulSet1()
 	cli := fake.NewClientBuilder().WithRuntimeObjects(statefulSet).Build()
-	result, err := findStatefulSet(context.TODO(), cli, namespace1, statefulSet1)
+	result, err := findStatefulSet(context.TODO(), cli, namespace1, statefulSet1Name)
 
 	assert.NoError(t, err)
 	assert.Equal(t, statefulSet, result)
@@ -152,14 +225,14 @@ func Test_findStatefulSet(t *testing.T) {
 
 func Test_findStatefulSetNotFound(t *testing.T) {
 	cli := fake.NewClientBuilder().Build()
-	_, err := findStatefulSet(context.TODO(), cli, namespace1, statefulSet1)
-	assert.ErrorContains(t, err, "\"statefulSet1\" not found")
+	_, err := findStatefulSet(context.TODO(), cli, namespace1, statefulSet1Name)
+	assert.ErrorContains(t, err, "\"statefulSet1Name\" not found")
 }
 
 func Test_findIngress(t *testing.T) {
 	ingress := mockIngress1()
 	cli := fake.NewClientBuilder().WithRuntimeObjects(ingress).Build()
-	result, err := findIngress(context.TODO(), cli, namespace1, ingress1)
+	result, err := findIngress(context.TODO(), cli, namespace1, ingress1Name)
 
 	assert.NoError(t, err)
 	assert.Equal(t, ingress, result)
@@ -167,59 +240,42 @@ func Test_findIngress(t *testing.T) {
 
 func Test_findIngressNotFound(t *testing.T) {
 	cli := fake.NewClientBuilder().Build()
-	_, err := findIngress(context.TODO(), cli, namespace1, ingress1)
-	assert.ErrorContains(t, err, "\"ingress1\" not found")
+	_, err := findIngress(context.TODO(), cli, namespace1, ingress1Name)
+	assert.ErrorContains(t, err, "\"ingress1Name\" not found")
 }
 
-func mockService1(labels *map[string]string) *corev1.Service {
-	return mockService(namespace1, service1, labels)
+func mockService1(selectorLabels *map[string]string) *corev1.Service {
+	return mockService(namespace1, service1Name, nil, selectorLabels)
+}
+
+func mockService2(selectorLabels *map[string]string) *corev1.Service {
+	return mockService(namespace1, service2Name, nil, selectorLabels)
+}
+
+func mockService3(selectorLabels *map[string]string) *corev1.Service {
+	return mockService(namespace1, service3Name, nil, selectorLabels)
 }
 
 func mockPod1(labels *map[string]string) *corev1.Pod {
-	return mockPod(namespace1, pod1, labels)
+	return mockPod(namespace1, pod1Name, labels)
+}
+
+func mockPod2(labels *map[string]string) *corev1.Pod {
+	return mockPod(namespace1, pod2Name, labels)
+}
+
+func mockPod3(labels *map[string]string) *corev1.Pod {
+	return mockPod(namespace1, pod3Name, labels)
 }
 
 func mockDeployment1(labels *map[string]string) *appsv1.Deployment {
-	deployment := &appsv1.Deployment{
-		TypeMeta: metav1.TypeMeta{
-			Kind:       "Deployment",
-			APIVersion: "apps/v1",
-		},
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace: namespace1,
-			Name:      deployment1,
-		},
-	}
-	if labels != nil {
-		deployment.ObjectMeta.Labels = *labels
-	}
-	return deployment
+	return mockDeployment(namespace1, deployment1Name, labels, nil)
 }
 
 func mockStatefulSet1() *appsv1.StatefulSet {
-	statefulSet := &appsv1.StatefulSet{
-		TypeMeta: metav1.TypeMeta{
-			Kind:       "StatefulSet",
-			APIVersion: "apps/v1",
-		},
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace: namespace1,
-			Name:      statefulSet1,
-		},
-	}
-	return statefulSet
+	return mockStatefulSet(namespace1, statefulSet1Name, nil, nil)
 }
 
 func mockIngress1() *networkingV1.Ingress {
-	ingress := &networkingV1.Ingress{
-		TypeMeta: metav1.TypeMeta{
-			Kind:       "Ingress",
-			APIVersion: "networking.k8s.io/v1",
-		},
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace: namespace1,
-			Name:      ingress1,
-		},
-	}
-	return ingress
+	return mockIngress(namespace1, ingress1Name)
 }
diff --git a/controllers/discovery/test_utils.go b/controllers/discovery/test_utils.go
index d56bfb05..b84b932b 100644
--- a/controllers/discovery/test_utils.go
+++ b/controllers/discovery/test_utils.go
@@ -1,45 +1,63 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
 import (
+	"fmt"
+
+	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
+	networkingV1 "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/types"
 )
 
 const (
-	namespace1   = "namespace1"
-	service1     = "service1"
-	deployment1  = "deployment1"
-	statefulSet1 = "statefulSet1"
-	pod1         = "pod1"
-	container1   = "container1"
-	container2   = "container2"
-	ingress1     = "ingress1"
-	label1       = "label1"
-	valueLabel1  = "valueLabel1"
-	label2       = "label2"
-	valueLabel2  = "valueLabel2"
-
-	customPortName = "my-custom-port"
-	defaultHttp    = 80
-	defaultHttps   = 443
-	tcp            = "TCP"
+	namespace1       = "namespace1"
+	service1Name     = "service1Name"
+	service2Name     = "service2Name"
+	service3Name     = "service3Name"
+	deployment1Name  = "deployment1Name"
+	statefulSet1Name = "statefulSet1Name"
+	pod1Name         = "pod1Name"
+	pod2Name         = "pod2Name"
+	pod3Name         = "pod3Name"
+	container1Name   = "container1Name"
+	container2Name   = "container2Name"
+	ingress1Name     = "ingress1Name"
+	label1           = "label1"
+	valueLabel1      = "valueLabel1"
+	label2           = "label2"
+	valueLabel2      = "valueLabel2"
+	label3           = "label3"
+	valueLabel3      = "valueLabel3"
+	customPortName   = "my-custom-port"
+	tcp              = "TCP"
+	uidOwner1        = "uidOwner1"
+	uidOwner2        = "uidOwner2"
+	replicaSet1Name  = "replicaSet1Name"
+	replicaSet2Name  = "replicaSet2Name"
+	replicaSet3Name  = "replicaSet3Name"
 )
 
-func mockService(namespace string, name string, labels *map[string]string) *corev1.Service {
+func mockService(namespace string, name string, labels *map[string]string, selectorLabels *map[string]string) *corev1.Service {
 	service := &corev1.Service{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "Service",
@@ -53,11 +71,14 @@ func mockService(namespace string, name string, labels *map[string]string) *core
 	if labels != nil {
 		service.ObjectMeta.Labels = *labels
 	}
+	if selectorLabels != nil {
+		service.Spec.Selector = *selectorLabels
+	}
 	return service
 }
 
 func mockServiceWithPorts(namespace string, name string, ports ...corev1.ServicePort) *corev1.Service {
-	service := mockService(namespace, name, &map[string]string{})
+	service := mockService(namespace, name, &map[string]string{}, nil)
 	service.Spec.Ports = ports
 	return service
 }
@@ -108,3 +129,75 @@ func mockContainerPort(name string, protocol string, port int32) corev1.Containe
 		Protocol:      corev1.Protocol(protocol),
 	}
 }
+
+func mockReplicaSet(namespace string, name string, ownerReferenceUID string) *appsv1.ReplicaSet {
+	replicaSet := &appsv1.ReplicaSet{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "ReplicaSet",
+			APIVersion: "apps/v1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace:       namespace,
+			Name:            name,
+			OwnerReferences: []metav1.OwnerReference{{UID: types.UID(ownerReferenceUID)}},
+			UID:             types.UID(fmt.Sprintf("%s-%s-mock-replicaset-uid", namespace, name)),
+		},
+	}
+	return replicaSet
+}
+
+func mockDeployment(namespace string, name string, labels *map[string]string, selector *map[string]string) *appsv1.Deployment {
+	deployment := &appsv1.Deployment{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "Deployment",
+			APIVersion: "apps/v1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+			UID:       types.UID(fmt.Sprintf("%s-%s-mock-deployment-uid", namespace, name)),
+		},
+	}
+	if labels != nil {
+		deployment.ObjectMeta.Labels = *labels
+	}
+	if selector != nil {
+		deployment.Spec.Selector = &metav1.LabelSelector{MatchLabels: *selector}
+	}
+	return deployment
+}
+
+func mockStatefulSet(namespace string, name string, labels *map[string]string, selector *map[string]string) *appsv1.StatefulSet {
+	statefulSet := &appsv1.StatefulSet{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "StatefulSet",
+			APIVersion: "apps/v1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+			UID:       types.UID(fmt.Sprintf("%s-%s-mock-statefulset-uid", namespace, name)),
+		},
+	}
+	if labels != nil {
+		statefulSet.ObjectMeta.Labels = *labels
+	}
+	if selector != nil {
+		statefulSet.Spec.Selector = &metav1.LabelSelector{MatchLabels: *selector}
+	}
+	return statefulSet
+}
+
+func mockIngress(namespace string, name string) *networkingV1.Ingress {
+	ingress := &networkingV1.Ingress{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "Ingress",
+			APIVersion: "networking.k8s.io/v1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+	}
+	return ingress
+}
diff --git a/controllers/discovery/uri_parser.go b/controllers/discovery/uri_parser.go
index 4f7425c6..1096780a 100644
--- a/controllers/discovery/uri_parser.go
+++ b/controllers/discovery/uri_parser.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -74,14 +79,13 @@ func parseKubernetesUri(uri string, schemaAndGroup string, after string) (*Resou
 		if queryParams, err = parseQueryParams(uri, split[1]); err != nil {
 			return nil, err
 		}
-
 		gvk, _ := parseGVK(schemaAndGroup)
 		return &ResourceUri{
-			Scheme:       KubernetesScheme,
-			GVK:          *gvk,
-			Namespace:    namespace,
-			Name:         name,
-			CustomLabels: queryParams,
+			Scheme:      KubernetesScheme,
+			GVK:         *gvk,
+			Namespace:   namespace,
+			Name:        name,
+			QueryParams: queryParams,
 		}, nil
 
 	} else {
diff --git a/controllers/discovery/uri_parser_test.go b/controllers/discovery/uri_parser_test.go
index 32cb158b..9b72d1d5 100644
--- a/controllers/discovery/uri_parser_test.go
+++ b/controllers/discovery/uri_parser_test.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -40,7 +45,7 @@ var KubernetesServicesTestValues = map[string]*ResourceUri{
 		Kind("services").
 		Version("v1").
 		Name("my-service").
-		WithLabel("label-a", "value-a").Build(),
+		WithQueryParam("label-a", "value-a").Build(),
 
 	"kubernetes:services.v1/my-service?label-a=value-a&": nil,
 
@@ -52,8 +57,8 @@ var KubernetesServicesTestValues = map[string]*ResourceUri{
 		Kind("services").
 		Version("v1").
 		Name("my-service").
-		WithLabel("label-a", "value-a").
-		WithLabel("label-b", "value-b").Build(),
+		WithQueryParam("label-a", "value-a").
+		WithQueryParam("label-b", "value-b").Build(),
 
 	"kubernetes:services.v1/my-namespace/": nil,
 
@@ -77,7 +82,7 @@ var KubernetesServicesTestValues = map[string]*ResourceUri{
 		Version("v1").
 		Namespace("my-namespace").
 		Name("my-service").
-		WithLabel("label-a", "value-a").Build(),
+		WithQueryParam("label-a", "value-a").Build(),
 
 	"kubernetes:services.v1/my-namespace/my-service?label-a=value-a&": nil,
 
@@ -85,13 +90,14 @@ var KubernetesServicesTestValues = map[string]*ResourceUri{
 
 	"kubernetes:services.v1/my-namespace/my-service?label-a=value-a&label-b=": nil,
 
-	"kubernetes:services.v1/my-namespace/my-service?label-a=value-a&label-b=value-b": NewResourceUriBuilder(KubernetesScheme).
+	"kubernetes:services.v1/my-namespace/my-service?label-a=value-a&label-b=value-b&port=custom-port-value": NewResourceUriBuilder(KubernetesScheme).
 		Kind("services").
 		Version("v1").
 		Namespace("my-namespace").
 		Name("my-service").
-		WithLabel("label-a", "value-a").
-		WithLabel("label-b", "value-b").Build(),
+		WithQueryParam("label-a", "value-a").
+		WithQueryParam("label-b", "value-b").
+		WithPort("custom-port-value").Build(),
 }
 
 func TestParseKubernetesServicesURI(t *testing.T) {
@@ -122,9 +128,9 @@ func assertEquals(t *testing.T, uri *ResourceUri, expectedUri *ResourceUri) {
 	assert.Equal(t, uri.GVK.Group, expectedUri.GVK.Group)
 	assert.Equal(t, uri.GVK.Version, expectedUri.GVK.Version)
 	assert.Equal(t, uri.GVK.Kind, expectedUri.GVK.Kind)
-	assert.Equal(t, len(uri.CustomLabels), len(expectedUri.CustomLabels))
-	for k, v := range uri.CustomLabels {
-		assert.True(t, len(expectedUri.CustomLabels[k]) > 0, "label %s is not present in expectedUri: %s", k, expectedUri.String())
-		assert.Equal(t, v, expectedUri.CustomLabels[k], "value for label %s in expectedUri should be %s, but is %s", k, v, expectedUri.CustomLabels[k])
+	assert.Equal(t, len(uri.QueryParams), len(expectedUri.QueryParams))
+	for k, v := range uri.QueryParams {
+		assert.True(t, len(expectedUri.QueryParams[k]) > 0, "label %s is not present in expectedUri: %s", k, expectedUri.String())
+		assert.Equal(t, v, expectedUri.QueryParams[k], "value for label %s in expectedUri should be %s, but is %s", k, v, expectedUri.QueryParams[k])
 	}
 }
diff --git a/controllers/discovery/uri_utils.go b/controllers/discovery/uri_utils.go
index 4c1de70e..a3092d5c 100644
--- a/controllers/discovery/uri_utils.go
+++ b/controllers/discovery/uri_utils.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -32,7 +37,7 @@ func resolveServiceUri(service *corev1.Service, customPort string, outputFormat
 	case corev1.ServiceTypeExternalName:
 		// ExternalName may not work properly with SSL:
 		// https://kubernetes.io/docs/concepts/services-networking/service/#externalname
-		protocol = httpProtocolName
+		protocol = httpProtocol
 		host = service.Spec.ExternalName
 		port = 80
 	case corev1.ServiceTypeClusterIP:
@@ -60,9 +65,9 @@ func resolveServiceUri(service *corev1.Service, customPort string, outputFormat
 func resolveClusterIPOrTypeNodeServiceUriParams(service *corev1.Service, customPort string) (protocol string, host string, port int) {
 	servicePort := findBestSuitedServicePort(service, customPort)
 	if isSecureServicePort(servicePort) {
-		protocol = httpsProtocolName
+		protocol = httpsProtocol
 	} else {
-		protocol = httpProtocolName
+		protocol = httpProtocol
 	}
 	host = service.Spec.ClusterIP
 	port = int(servicePort.Port)
@@ -83,9 +88,9 @@ func resolvePodUri(pod *corev1.Pod, customContainer string, customPort string, o
 		if containerPort := findBestSuitedContainerPort(container, customPort); containerPort == nil {
 			return "", fmt.Errorf("no container port was found for pod: %s in namespace: %s", pod.Name, pod.Namespace)
 		} else {
-			protocol := httpProtocolName
+			protocol := httpProtocol
 			if isSecure := isSecureContainerPort(containerPort); isSecure {
-				protocol = httpsProtocolName
+				protocol = httpsProtocol
 			}
 			if outputFormat == KubernetesDNSAddress {
 				return buildKubernetesPodDNSUri(protocol, pod.Namespace, podIp, int(containerPort.ContainerPort)), nil
diff --git a/controllers/discovery/uri_utils_test.go b/controllers/discovery/uri_utils_test.go
index 6c5fa703..3d296114 100644
--- a/controllers/discovery/uri_utils_test.go
+++ b/controllers/discovery/uri_utils_test.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package discovery
 
@@ -22,35 +27,35 @@ import (
 )
 
 func Test_resolveServiceUriClusterIPServiceDNSMode(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort(httpProtocolName, tcp, defaultHttp))
-	doTestResolveServiceUri(t, service, corev1.ServiceTypeClusterIP, KubernetesDNSAddress, "http://service1.namespace1.svc:80")
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort(httpProtocol, tcp, defaultHttpPort))
+	doTestResolveServiceUri(t, service, corev1.ServiceTypeClusterIP, KubernetesDNSAddress, "http://service1Name.namespace1.svc:80")
 }
 
 func Test_resolveServiceUriClusterIPServiceIPAddressMode(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort(httpProtocolName, tcp, defaultHttp))
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort(httpProtocol, tcp, defaultHttpPort))
 	service.Spec.ClusterIP = "10.1.15.16"
 	doTestResolveServiceUri(t, service, corev1.ServiceTypeClusterIP, KubernetesIPAddress, "http://10.1.15.16:80")
 }
 
 func Test_resolveServiceUriNodeTypeServiceDNSMode(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort(httpProtocolName, tcp, defaultHttp))
-	doTestResolveServiceUri(t, service, corev1.ServiceTypeNodePort, KubernetesDNSAddress, "http://service1.namespace1.svc:80")
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort(httpProtocol, tcp, defaultHttpPort))
+	doTestResolveServiceUri(t, service, corev1.ServiceTypeNodePort, KubernetesDNSAddress, "http://service1Name.namespace1.svc:80")
 }
 
 func Test_resolveServiceUriNodeTypeServiceIPAddressMode(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort(httpProtocolName, tcp, defaultHttp))
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort(httpProtocol, tcp, defaultHttpPort))
 	service.Spec.ClusterIP = "10.1.15.16"
 	doTestResolveServiceUri(t, service, corev1.ServiceTypeNodePort, KubernetesIPAddress, "http://10.1.15.16:80")
 }
 
 func Test_resolveServiceUriExternalNameServiceDNSMode(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort(httpProtocolName, tcp, defaultHttp))
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort(httpProtocol, tcp, defaultHttpPort))
 	service.Spec.ExternalName = "external.service.com"
 	doTestResolveServiceUri(t, service, corev1.ServiceTypeExternalName, KubernetesIPAddress, "http://external.service.com:80")
 }
 
 func Test_resolveServiceUriExternalNameServiceIPAddressMode(t *testing.T) {
-	service := mockServiceWithPorts(namespace1, service1, mockServicePort(httpProtocolName, tcp, defaultHttp))
+	service := mockServiceWithPorts(namespace1, service1Name, mockServicePort(httpProtocol, tcp, defaultHttpPort))
 	service.Spec.ExternalName = "external.service.com"
 	doTestResolveServiceUri(t, service, corev1.ServiceTypeExternalName, KubernetesIPAddress, "http://external.service.com:80")
 }
@@ -63,40 +68,40 @@ func doTestResolveServiceUri(t *testing.T, service *corev1.Service, serviceType
 }
 
 func Test_resolvePodUriDNSMode(t *testing.T) {
-	pod := mockPodWithContainers(namespace1, pod1,
-		*mockContainerWithPorts(container1, mockContainerPort(httpProtocolName, tcp, defaultHttp)),
-		*mockContainerWithPorts(container2, mockContainerPort(httpsProtocolName, tcp, defaultHttps)))
+	pod := mockPodWithContainers(namespace1, pod1Name,
+		*mockContainerWithPorts(container1Name, mockContainerPort(httpProtocol, tcp, defaultHttpPort)),
+		*mockContainerWithPorts(container2Name, mockContainerPort(httpsProtocol, tcp, defaultHttpsPort)))
 	pod.Status.PodIP = "10.1.15.16"
 	doTestResolvePodUri(t, pod, "", "", KubernetesDNSAddress, "http://10-1-15-16.namespace1.pod:80")
 }
 
 func Test_resolvePodUriIPAddressMode(t *testing.T) {
-	pod := mockPodWithContainers(namespace1, pod1,
-		*mockContainerWithPorts(container1, mockContainerPort(httpProtocolName, tcp, defaultHttp)),
-		*mockContainerWithPorts(container2, mockContainerPort(httpsProtocolName, tcp, defaultHttps)))
+	pod := mockPodWithContainers(namespace1, pod1Name,
+		*mockContainerWithPorts(container1Name, mockContainerPort(httpProtocol, tcp, defaultHttpPort)),
+		*mockContainerWithPorts(container2Name, mockContainerPort(httpsProtocol, tcp, defaultHttpsPort)))
 	pod.Status.PodIP = "10.1.15.17"
 	doTestResolvePodUri(t, pod, "", "", KubernetesIPAddress, "http://10.1.15.17:80")
 }
 
 func Test_resolvePodUriByCustomContainerDNSMode(t *testing.T) {
-	pod := mockPodWithContainers(namespace1, pod1,
-		*mockContainerWithPorts(container1, mockContainerPort(httpsProtocolName, tcp, defaultHttps)),
-		*mockContainerWithPorts("custom-container", mockContainerPort(httpProtocolName, tcp, defaultHttp)))
+	pod := mockPodWithContainers(namespace1, pod1Name,
+		*mockContainerWithPorts(container1Name, mockContainerPort(httpsProtocol, tcp, defaultHttpsPort)),
+		*mockContainerWithPorts("custom-container", mockContainerPort(httpProtocol, tcp, defaultHttpPort)))
 	pod.Status.PodIP = "10.1.15.16"
 	doTestResolvePodUri(t, pod, "custom-container", "", KubernetesDNSAddress, "http://10-1-15-16.namespace1.pod:80")
 }
 
 func Test_resolvePodUriByCustomContainerIPAddressMode(t *testing.T) {
-	pod := mockPodWithContainers(namespace1, pod1,
-		*mockContainerWithPorts(container1, mockContainerPort(httpsProtocolName, tcp, defaultHttps)),
-		*mockContainerWithPorts("custom-container", mockContainerPort(httpProtocolName, tcp, defaultHttp)))
+	pod := mockPodWithContainers(namespace1, pod1Name,
+		*mockContainerWithPorts(container1Name, mockContainerPort(httpsProtocol, tcp, defaultHttpsPort)),
+		*mockContainerWithPorts("custom-container", mockContainerPort(httpProtocol, tcp, defaultHttpPort)))
 	pod.Status.PodIP = "10.1.15.17"
 	doTestResolvePodUri(t, pod, "custom-container", "", KubernetesIPAddress, "http://10.1.15.17:80")
 }
 
 func Test_resolvePodUriByCustomContainerAndCustomPortDNSMode(t *testing.T) {
-	pod := mockPodWithContainers(namespace1, pod1,
-		*mockContainerWithPorts(container1, mockContainerPort(httpsProtocolName, tcp, defaultHttps)),
+	pod := mockPodWithContainers(namespace1, pod1Name,
+		*mockContainerWithPorts(container1Name, mockContainerPort(httpsProtocol, tcp, defaultHttpsPort)),
 		*mockContainerWithPorts("custom-container",
 			mockContainerPort("not-wanted", tcp, 8008),
 			mockContainerPort("custom-port", tcp, 8181)))
@@ -105,8 +110,8 @@ func Test_resolvePodUriByCustomContainerAndCustomPortDNSMode(t *testing.T) {
 }
 
 func Test_resolvePodUriByCustomContainerAndCustomPortIPAddressMode(t *testing.T) {
-	pod := mockPodWithContainers(namespace1, pod1,
-		*mockContainerWithPorts(container1, mockContainerPort(httpsProtocolName, tcp, defaultHttps)),
+	pod := mockPodWithContainers(namespace1, pod1Name,
+		*mockContainerWithPorts(container1Name, mockContainerPort(httpsProtocol, tcp, defaultHttpsPort)),
 		*mockContainerWithPorts("custom-container",
 			mockContainerPort("not-wanted", tcp, 8008),
 			mockContainerPort("custom-port", tcp, 8181)))
@@ -125,9 +130,9 @@ func Test_buildURI(t *testing.T) {
 }
 
 func Test_buildKubernetesServiceDNSUri(t *testing.T) {
-	assert.Equal(t, "http://service1.namespace1.svc:8383", buildKubernetesServiceDNSUri("http", namespace1, service1, 8383))
+	assert.Equal(t, "http://service1Name.namespace1.svc:8383", buildKubernetesServiceDNSUri("http", namespace1, service1Name, 8383))
 }
 
 func Test_buildKubernetesPodDNSUri(t *testing.T) {
-	assert.Equal(t, "http://pod1.namespace1.pod:8484", buildKubernetesPodDNSUri("http", namespace1, pod1, 8484))
+	assert.Equal(t, "http://pod1Name.namespace1.pod:8484", buildKubernetesPodDNSUri("http", namespace1, pod1Name, 8484))
 }
diff --git a/controllers/profiles/common/app_properties.go b/controllers/profiles/common/app_properties.go
index f97e9934..9564d160 100644
--- a/controllers/profiles/common/app_properties.go
+++ b/controllers/profiles/common/app_properties.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package common
 
diff --git a/controllers/profiles/common/app_properties_test.go b/controllers/profiles/common/app_properties_test.go
index f3d46f07..8fae160d 100644
--- a/controllers/profiles/common/app_properties_test.go
+++ b/controllers/profiles/common/app_properties_test.go
@@ -1,16 +1,21 @@
-// Copyright 2023 Red Hat, Inc. and/or its affiliates
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 package common
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org