func()

in pkg/appgw/istio_settings.go [51:183]


func (c *appGwConfigBuilder) getIstioDestinationsAndSettingsMap(cbCtx *ConfigBuilderContext) ([]n.ApplicationGatewayBackendHTTPSettings, map[istioDestinationIdentifier]*n.ApplicationGatewayBackendHTTPSettings, map[istioDestinationIdentifier]serviceBackendPortPair, error) {
	serviceBackendPairsMap := make(map[istioDestinationIdentifier]map[serviceBackendPortPair]interface{})
	backendHTTPSettingsMap := make(map[istioDestinationIdentifier]*n.ApplicationGatewayBackendHTTPSettings)
	finalServiceBackendPairMap := make(map[istioDestinationIdentifier]serviceBackendPortPair)

	var unresolvedDestinationID []istioDestinationIdentifier
	_, destinationIDs := istioMatchDestinationIds(cbCtx)
	for destinationID := range destinationIDs {
		resolvedBackendPorts := make(map[serviceBackendPortPair]interface{})

		service := c.k8sContext.GetService(destinationID.serviceKey())
		destinationPortNum := Port(destinationID.DestinationPort)
		if service == nil {
			// Once services are filtered in the istioMatchDestinationIDs function, this should never happen
			logLine := fmt.Sprintf("Unable to get the service [%s]", destinationID.serviceKey())
			klog.Errorf(logLine)
			// TODO(rhea): add error event
			pair := serviceBackendPortPair{
				ServicePort: Port(destinationPortNum),
				BackendPort: Port(destinationPortNum),
			}
			resolvedBackendPorts[pair] = nil
		} else {
			for _, sp := range service.Spec.Ports {
				// find the backend port number
				// check if any service ports matches the specified ports
				if sp.Protocol != v1.ProtocolTCP {
					// ignore UDP ports
					continue
				}

				// TODO(delqn): implement correctly port lookup by name
				if Port(sp.Port) == destinationPortNum || sp.TargetPort.String() == fmt.Sprint(destinationPortNum) {
					// matched a service port with a port from the service
					if sp.TargetPort.String() == "" {
						// targetPort is not defined, by default targetPort == port
						pair := serviceBackendPortPair{
							ServicePort: Port(sp.Port),
							BackendPort: Port(sp.Port),
						}
						resolvedBackendPorts[pair] = nil
					} else {
						// target port is defined as name or port number
						if sp.TargetPort.Type == intstr.Int {
							// port is defined as port number
							pair := serviceBackendPortPair{
								ServicePort: Port(sp.Port),
								BackendPort: Port(sp.TargetPort.IntVal),
							}
							resolvedBackendPorts[pair] = nil
						} else {
							// if service port is defined by name, need to resolve
							targetPortName := sp.TargetPort.StrVal
							klog.V(1).Infof("resolving port name %s", targetPortName)
							targetPortsResolved := c.resolveIstioPortName(targetPortName, &destinationID)
							for targetPort := range targetPortsResolved {
								pair := serviceBackendPortPair{
									ServicePort: Port(sp.Port),
									BackendPort: Port(targetPort),
								}
								resolvedBackendPorts[pair] = nil
							}
						}
					}
					break
				}
			}
		}
		if len(resolvedBackendPorts) == 0 {
			logLine := fmt.Sprintf("Unable to resolve any backend port for service [%s]", destinationID.serviceKey())
			klog.Error(logLine)
			//TODO(rhea): Add error event

			unresolvedDestinationID = append(unresolvedDestinationID, destinationID)
			break
		}

		// Merge serviceBackendPairsMap[backendID] into resolvedBackendPorts
		if _, ok := serviceBackendPairsMap[destinationID]; !ok {
			serviceBackendPairsMap[destinationID] = make(map[serviceBackendPortPair]interface{})
		}
		for portPair := range resolvedBackendPorts {
			serviceBackendPairsMap[destinationID][portPair] = nil
		}
	}
	if len(unresolvedDestinationID) > 0 {
		e := controllererrors.NewError(
			controllererrors.ErrorIstioResolvePortsForServices,
			"unable to resolve backend port for some services",
		)
		return nil, nil, nil, e
	}

	httpSettingsCollection := make(map[string]n.ApplicationGatewayBackendHTTPSettings)
	for destinationID, serviceBackendPairs := range serviceBackendPairsMap {
		if len(serviceBackendPairs) > 1 {
			// more than one possible backend port exposed through ingress
			backendServicePort := ""
			if destinationID.DestinationPort != 0 {
				backendServicePort = fmt.Sprint(destinationID.DestinationPort)
			} else {
				// TODO(delqn): implement port lookup by name
			}

			//TODO(rhea): add error event recorder
			e := controllererrors.NewErrorf(
				controllererrors.ErrorIstioMultipleServiceBackendPortBinding,
				"service:port [%s:%s] has more than one service-backend port binding",
				destinationID.serviceKey(), backendServicePort,
			)
			klog.Warning(e.Error())
			return nil, nil, nil, e
		}

		// At this point there will be only one pair
		var uniquePair serviceBackendPortPair
		for k := range serviceBackendPairs {
			uniquePair = k
		}

		finalServiceBackendPairMap[destinationID] = uniquePair
		httpSettings := c.generateIstioHTTPSettings(destinationID, uniquePair.BackendPort, cbCtx)
		httpSettingsCollection[*httpSettings.Name] = httpSettings
		backendHTTPSettingsMap[destinationID] = &httpSettings
	}

	httpSettings := make([]n.ApplicationGatewayBackendHTTPSettings, 0, len(httpSettingsCollection))
	for _, backend := range httpSettingsCollection {
		httpSettings = append(httpSettings, backend)
	}

	return httpSettings, backendHTTPSettingsMap, finalServiceBackendPairMap, nil
}