|
1 | 1 | package resourcevisibility |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "cmp" |
| 5 | + "context" |
4 | 6 | "github.com/otterize/intents-operator/src/shared/errors" |
5 | 7 | "github.com/otterize/network-mapper/src/mapper/pkg/cloudclient" |
6 | 8 | "github.com/otterize/nilable" |
7 | 9 | "github.com/samber/lo" |
8 | 10 | "github.com/sirupsen/logrus" |
| 11 | + "golang.org/x/exp/slices" |
9 | 12 | corev1 "k8s.io/api/core/v1" |
10 | 13 | networkingv1 "k8s.io/api/networking/v1" |
11 | 14 | "k8s.io/apimachinery/pkg/util/intstr" |
| 15 | + "sigs.k8s.io/controller-runtime/pkg/client" |
12 | 16 | ) |
13 | 17 |
|
14 | 18 | func convertPortProtocol(protocol corev1.Protocol) (*cloudclient.K8sPortProtocol, error) { |
@@ -294,7 +298,7 @@ func convertIngressLoadBalancerStatus(status networkingv1.IngressStatus) (nilabl |
294 | 298 | return nilable.From(ingressStatusInput), nil |
295 | 299 | } |
296 | 300 |
|
297 | | -func convertServiceResource(service corev1.Service) (cloudclient.K8sResourceServiceInput, error) { |
| 301 | +func convertServiceResource(ctx context.Context, k8sClient client.Client, service corev1.Service) (cloudclient.K8sResourceServiceInput, error) { |
298 | 302 | ports := make([]cloudclient.K8sServicePort, 0) |
299 | 303 | for _, port := range service.Spec.Ports { |
300 | 304 | protocol, err := convertPortProtocol(port.Protocol) |
@@ -391,6 +395,11 @@ func convertServiceResource(service corev1.Service) (cloudclient.K8sResourceServ |
391 | 395 | input.Status = status |
392 | 396 | } |
393 | 397 |
|
| 398 | + targetNamedPorts := getRelatedPodsNamedPortsMap(ctx, k8sClient, &service) |
| 399 | + if len(targetNamedPorts) > 0 { |
| 400 | + input.TargetNamedPorts = targetNamedPorts |
| 401 | + } |
| 402 | + |
394 | 403 | return input, nil |
395 | 404 | } |
396 | 405 |
|
@@ -565,3 +574,60 @@ func convertIngressResource(ingress networkingv1.Ingress) (cloudclient.K8sResour |
565 | 574 |
|
566 | 575 | return input, true, nil |
567 | 576 | } |
| 577 | + |
| 578 | +func getRelatedPodsNamedPortsMap(ctx context.Context, k8sClient client.Client, service *corev1.Service) []cloudclient.NamedPortInput { |
| 579 | + if len(service.Spec.Selector) == 0 { |
| 580 | + return nil |
| 581 | + } |
| 582 | + relatedPods := &corev1.PodList{} |
| 583 | + labelSelector := client.MatchingLabels(service.Spec.Selector) |
| 584 | + err := k8sClient.List(ctx, relatedPods, labelSelector, client.InNamespace(service.Namespace)) |
| 585 | + if err != nil { |
| 586 | + logrus.WithFields(logrus.Fields{"service": service.Name, "namespace": service.Namespace}).WithError(err).Errorf("Failed listing pods for service") |
| 587 | + return nil |
| 588 | + } |
| 589 | + |
| 590 | + namedPorts := make([]cloudclient.NamedPortInput, 0) |
| 591 | + for _, pod := range relatedPods.Items { |
| 592 | + for _, container := range pod.Spec.Containers { |
| 593 | + for _, port := range container.Ports { |
| 594 | + if port.Name == "" { |
| 595 | + continue // We are only interested in named ports |
| 596 | + } |
| 597 | + namedPorts = append(namedPorts, cloudclient.NamedPortInput{ |
| 598 | + Name: port.Name, |
| 599 | + Port: int(port.ContainerPort), |
| 600 | + Protocol: convertProtocolToCloudFormat(port.Protocol), |
| 601 | + }) |
| 602 | + } |
| 603 | + } |
| 604 | + } |
| 605 | + |
| 606 | + namedPorts = lo.Uniq(namedPorts) |
| 607 | + slices.SortFunc(namedPorts, func(a, b cloudclient.NamedPortInput) int { |
| 608 | + if cmp.Compare(a.Name, b.Name) != 0 { |
| 609 | + return cmp.Compare(a.Name, b.Name) |
| 610 | + } |
| 611 | + if cmp.Compare(a.Port, b.Port) != 0 { |
| 612 | + return cmp.Compare(a.Port, b.Port) |
| 613 | + } |
| 614 | + if cmp.Compare(a.Protocol, b.Protocol) != 0 { |
| 615 | + return cmp.Compare(a.Protocol, b.Protocol) |
| 616 | + } |
| 617 | + return 0 |
| 618 | + }) |
| 619 | + return namedPorts |
| 620 | +} |
| 621 | + |
| 622 | +func convertProtocolToCloudFormat(proto corev1.Protocol) cloudclient.K8sPortProtocol { |
| 623 | + switch proto { |
| 624 | + case corev1.ProtocolTCP: |
| 625 | + return cloudclient.K8sPortProtocolTcp |
| 626 | + case corev1.ProtocolUDP: |
| 627 | + return cloudclient.K8sPortProtocolUdp |
| 628 | + case corev1.ProtocolSCTP: |
| 629 | + return cloudclient.K8sPortProtocolSctp |
| 630 | + default: |
| 631 | + return cloudclient.K8sPortProtocolTcp |
| 632 | + } |
| 633 | +} |
0 commit comments