in pkg/ingress/kube/gateway/istio/conversion.go [1146:1236]
func buildDestination(ctx configContext, to k8s.BackendRef, ns string, enforceRefGrant bool) (*istio.Destination, *ConfigError) {
// check if the reference is allowed
if enforceRefGrant {
refs := ctx.AllowedReferences
if toNs := to.Namespace; toNs != nil && string(*toNs) != ns {
if !refs.BackendAllowed(gvk.HTTPRoute, to.Name, *toNs, ns) {
return &istio.Destination{}, &ConfigError{
Reason: InvalidDestinationPermit,
Message: fmt.Sprintf("backendRef %v/%v not accessible to a route in namespace %q (missing a ReferenceGrant?)", to.Name, *toNs, ns),
}
}
}
}
namespace := ptr.OrDefault((*string)(to.Namespace), ns)
var invalidBackendErr *ConfigError
if nilOrEqual((*string)(to.Group), "") && nilOrEqual((*string)(to.Kind), gvk.Service.Kind) {
// Service
if to.Port == nil {
// "Port is required when the referent is a Kubernetes Service."
return nil, &ConfigError{Reason: InvalidDestination, Message: "port is required in backendRef"}
}
if strings.Contains(string(to.Name), ".") {
return nil, &ConfigError{Reason: InvalidDestination, Message: "serviceName invalid; the name of the Service must be used, not the hostname."}
}
hostname := fmt.Sprintf("%s.%s.svc.%s", to.Name, namespace, ctx.Domain)
if ctx.Context.GetService(hostname, namespace, gvk.Service.Kind) == nil {
invalidBackendErr = &ConfigError{Reason: InvalidDestinationNotFound, Message: fmt.Sprintf("backend(%s) not found", hostname)}
}
return &istio.Destination{
// TODO: implement ReferencePolicy for cross namespace
Host: hostname,
Port: &istio.PortSelector{Number: uint32(*to.Port)},
}, invalidBackendErr
}
if nilOrEqual((*string)(to.Group), features.MCSAPIGroup) && nilOrEqual((*string)(to.Kind), "ServiceImport") {
// Service import
hostname := fmt.Sprintf("%s.%s.svc.clusterset.local", to.Name, namespace)
if !features.EnableMCSHost {
// They asked for ServiceImport, but actually don't have full support enabled...
// No problem, we can just treat it as Service, which is already cross-cluster in this mode anyways
hostname = fmt.Sprintf("%s.%s.svc.%s", to.Name, namespace, ctx.Domain)
}
if to.Port == nil {
// We don't know where to send without port
return nil, &ConfigError{Reason: InvalidDestination, Message: "port is required in backendRef"}
}
if strings.Contains(string(to.Name), ".") {
return nil, &ConfigError{Reason: InvalidDestination, Message: "serviceName invalid; the name of the Service must be used, not the hostname."}
}
if ctx.Context.GetService(hostname, namespace, "ServiceImport") == nil {
invalidBackendErr = &ConfigError{Reason: InvalidDestinationNotFound, Message: fmt.Sprintf("backend(%s) not found", hostname)}
}
return &istio.Destination{
Host: hostname,
Port: &istio.PortSelector{Number: uint32(*to.Port)},
}, invalidBackendErr
}
if nilOrEqual((*string)(to.Group), gvk.ServiceEntry.Group) && nilOrEqual((*string)(to.Kind), "Hostname") {
// Hostname synthetic type
if to.Port == nil {
// We don't know where to send without port
return nil, &ConfigError{Reason: InvalidDestination, Message: "port is required in backendRef"}
}
if to.Namespace != nil {
return nil, &ConfigError{Reason: InvalidDestination, Message: "namespace may not be set with Hostname type"}
}
hostname := string(to.Name)
if ctx.Context.GetService(hostname, namespace, "Hostname") == nil {
invalidBackendErr = &ConfigError{Reason: InvalidDestinationNotFound, Message: fmt.Sprintf("backend(%s) not found", hostname)}
}
return &istio.Destination{
Host: string(to.Name),
Port: &istio.PortSelector{Number: uint32(*to.Port)},
}, invalidBackendErr
}
if equal((*string)(to.Group), "networking.higress.io") && nilOrEqual((*string)(to.Kind), "Service") {
var port *istio.PortSelector
if to.Port != nil {
port = &istio.PortSelector{Number: uint32(*to.Port)}
}
return &istio.Destination{
Host: string(to.Name),
Port: port,
}, nil
}
return &istio.Destination{}, &ConfigError{
Reason: InvalidDestinationKind,
Message: fmt.Sprintf("referencing unsupported backendRef: group %q kind %q", ptr.OrEmpty(to.Group), ptr.OrEmpty(to.Kind)),
}
}