istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/serviceregistry/kube/controller/endpoint_builder.go (about)

     1  // Copyright Istio Authors. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package controller
    16  
    17  import (
    18  	v1 "k8s.io/api/core/v1"
    19  
    20  	"istio.io/api/label"
    21  	"istio.io/istio/pilot/pkg/model"
    22  	"istio.io/istio/pilot/pkg/networking/util"
    23  	"istio.io/istio/pilot/pkg/serviceregistry/kube"
    24  	labelutil "istio.io/istio/pilot/pkg/serviceregistry/util/label"
    25  	"istio.io/istio/pkg/config/labels"
    26  	kubeUtil "istio.io/istio/pkg/kube"
    27  	"istio.io/istio/pkg/network"
    28  )
    29  
    30  // EndpointBuilder is a stateful IstioEndpoint builder with metadata used to build IstioEndpoint
    31  type EndpointBuilder struct {
    32  	controller controllerInterface
    33  
    34  	labels         labels.Instance
    35  	metaNetwork    network.ID
    36  	serviceAccount string
    37  	locality       model.Locality
    38  	tlsMode        string
    39  	workloadName   string
    40  	namespace      string
    41  
    42  	// Values used to build dns name tables per pod.
    43  	// The hostname of the Pod, by default equals to pod name.
    44  	hostname string
    45  	// If specified, the fully qualified Pod hostname will be "<hostname>.<subdomain>.<pod namespace>.svc.<cluster domain>".
    46  	subDomain string
    47  	// If in k8s, the node where the pod resides
    48  	nodeName string
    49  }
    50  
    51  func NewEndpointBuilder(c controllerInterface, pod *v1.Pod) *EndpointBuilder {
    52  	var locality, sa, namespace, hostname, subdomain, ip, node string
    53  	var podLabels labels.Instance
    54  	if pod != nil {
    55  		locality = c.getPodLocality(pod)
    56  		sa = kube.SecureNamingSAN(pod)
    57  		podLabels = pod.Labels
    58  		namespace = pod.Namespace
    59  		subdomain = pod.Spec.Subdomain
    60  		if subdomain != "" {
    61  			hostname = pod.Spec.Hostname
    62  			if hostname == "" {
    63  				hostname = pod.Name
    64  			}
    65  		}
    66  		ip = pod.Status.PodIP
    67  		node = pod.Spec.NodeName
    68  	}
    69  	dm, _ := kubeUtil.GetDeployMetaFromPod(pod)
    70  	out := &EndpointBuilder{
    71  		controller:     c,
    72  		serviceAccount: sa,
    73  		locality: model.Locality{
    74  			Label:     locality,
    75  			ClusterID: c.Cluster(),
    76  		},
    77  		tlsMode:      kube.PodTLSMode(pod),
    78  		workloadName: dm.Name,
    79  		namespace:    namespace,
    80  		hostname:     hostname,
    81  		subDomain:    subdomain,
    82  		labels:       podLabels,
    83  		nodeName:     node,
    84  	}
    85  	networkID := out.endpointNetwork(ip)
    86  	out.labels = labelutil.AugmentLabels(podLabels, c.Cluster(), locality, node, networkID)
    87  	return out
    88  }
    89  
    90  func NewEndpointBuilderFromMetadata(c controllerInterface, proxy *model.Proxy) *EndpointBuilder {
    91  	locality := util.LocalityToString(proxy.Locality)
    92  	out := &EndpointBuilder{
    93  		controller:     c,
    94  		metaNetwork:    proxy.Metadata.Network,
    95  		serviceAccount: proxy.Metadata.ServiceAccount,
    96  		locality: model.Locality{
    97  			Label:     locality,
    98  			ClusterID: c.Cluster(),
    99  		},
   100  		tlsMode:  model.GetTLSModeFromEndpointLabels(proxy.Labels),
   101  		nodeName: proxy.GetNodeName(),
   102  	}
   103  	var networkID network.ID
   104  	if len(proxy.IPAddresses) > 0 {
   105  		networkID = out.endpointNetwork(proxy.IPAddresses[0])
   106  	}
   107  	out.labels = labelutil.AugmentLabels(proxy.Labels, c.Cluster(), locality, out.nodeName, networkID)
   108  	return out
   109  }
   110  
   111  func (b *EndpointBuilder) buildIstioEndpoint(
   112  	endpointAddress string,
   113  	endpointPort int32,
   114  	svcPortName string,
   115  	discoverabilityPolicy model.EndpointDiscoverabilityPolicy,
   116  	healthStatus model.HealthStatus,
   117  ) *model.IstioEndpoint {
   118  	if b == nil {
   119  		return nil
   120  	}
   121  
   122  	// in case pod is not found when init EndpointBuilder.
   123  	networkID := network.ID(b.labels[label.TopologyNetwork.Name])
   124  	if networkID == "" {
   125  		networkID = b.endpointNetwork(endpointAddress)
   126  		b.labels[label.TopologyNetwork.Name] = string(networkID)
   127  	}
   128  
   129  	return &model.IstioEndpoint{
   130  		Labels:                b.labels,
   131  		ServiceAccount:        b.serviceAccount,
   132  		Locality:              b.locality,
   133  		TLSMode:               b.tlsMode,
   134  		Address:               endpointAddress,
   135  		EndpointPort:          uint32(endpointPort),
   136  		ServicePortName:       svcPortName,
   137  		Network:               networkID,
   138  		WorkloadName:          b.workloadName,
   139  		Namespace:             b.namespace,
   140  		HostName:              b.hostname,
   141  		SubDomain:             b.subDomain,
   142  		DiscoverabilityPolicy: discoverabilityPolicy,
   143  		HealthStatus:          healthStatus,
   144  		NodeName:              b.nodeName,
   145  	}
   146  }
   147  
   148  // return the mesh network for the endpoint IP. Empty string if not found.
   149  func (b *EndpointBuilder) endpointNetwork(endpointIP string) network.ID {
   150  	// If we're building the endpoint based on proxy meta, prefer the injected ISTIO_META_NETWORK value.
   151  	if b.metaNetwork != "" {
   152  		return b.metaNetwork
   153  	}
   154  
   155  	return b.controller.Network(endpointIP, b.labels)
   156  }