in pkg/openstack/loadbalancer.go [1540:1728]
func (lbaas *LbaasV2) checkService(service *corev1.Service, nodes []*corev1.Node, svcConf *serviceConfig) error {
serviceName := fmt.Sprintf("%s/%s", service.Namespace, service.Name)
if len(nodes) == 0 {
return fmt.Errorf("there are no available nodes for LoadBalancer service %s", serviceName)
}
ports := service.Spec.Ports
if len(ports) == 0 {
return fmt.Errorf("no service ports provided")
}
svcConf.lbID = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerID, "")
svcConf.supportLBTags = openstackutil.IsOctaviaFeatureSupported(lbaas.lb, openstackutil.OctaviaFeatureTags, lbaas.opts.LBProvider)
// If in the config file internal-lb=true, user is not allowed to create external service.
if lbaas.opts.InternalLB {
svcConf.internal = true
} else {
svcConf.internal = getBoolFromServiceAnnotation(service, ServiceAnnotationLoadBalancerInternal, lbaas.opts.InternalLB)
}
svcConf.tlsContainerRef = getStringFromServiceAnnotation(service, ServiceAnnotationTlsContainerRef, lbaas.opts.TlsContainerRef)
if svcConf.tlsContainerRef != "" {
if lbaas.secret == nil {
return fmt.Errorf("failed to create a TLS Terminated loadbalancer because openstack keymanager client is not "+
"initialized and default-tls-container-ref %q is set", svcConf.tlsContainerRef)
}
// check if container exists
// tls container ref has the format: https://{keymanager_host}/v1/containers/{uuid}
slice := strings.Split(svcConf.tlsContainerRef, "/")
containerID := slice[len(slice)-1]
container, err := containers.Get(lbaas.secret, containerID).Extract()
if err != nil {
return fmt.Errorf("failed to get tls container %q: %v", svcConf.tlsContainerRef, err)
}
klog.V(4).Infof("Default TLS container %q found", container.ContainerRef)
}
svcConf.connLimit = getIntFromServiceAnnotation(service, ServiceAnnotationLoadBalancerConnLimit, -1)
svcConf.lbNetworkID = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerNetworkID, lbaas.opts.NetworkID)
svcConf.lbSubnetID = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerSubnetID, lbaas.opts.SubnetID)
if lbaas.opts.SubnetID != "" {
svcConf.lbMemberSubnetID = lbaas.opts.SubnetID
} else {
svcConf.lbMemberSubnetID = svcConf.lbSubnetID
}
if len(svcConf.lbNetworkID) == 0 && len(svcConf.lbSubnetID) == 0 {
subnetID, err := getSubnetIDForLB(lbaas.compute, *nodes[0])
if err != nil {
return fmt.Errorf("failed to get subnet to create load balancer for service %s: %v", serviceName, err)
}
svcConf.lbSubnetID = subnetID
svcConf.lbMemberSubnetID = subnetID
lbaas.opts.SubnetID = subnetID
}
if !svcConf.internal {
var lbClass *LBClass
var floatingNetworkID string
var floatingSubnet floatingSubnetSpec
klog.V(4).Infof("Ensure an external loadbalancer service")
svcConf.configClassName = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerClass, "")
if svcConf.configClassName != "" {
lbClass = lbaas.opts.LBClasses[svcConf.configClassName]
if lbClass == nil {
return fmt.Errorf("invalid loadbalancer class %q", svcConf.configClassName)
}
klog.V(4).Infof("Found loadbalancer class %q with %+v", svcConf.configClassName, lbClass)
// Get floating network id and floating subnet id from loadbalancer class
floatingNetworkID = lbClass.FloatingNetworkID
floatingSubnet.subnetID = lbClass.FloatingSubnetID
if floatingSubnet.subnetID == "" {
floatingSubnet.subnet = lbClass.FloatingSubnet
floatingSubnet.subnetTags = lbClass.FloatingSubnetTags
}
}
if floatingNetworkID == "" {
floatingNetworkID = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerFloatingNetworkID, lbaas.opts.FloatingNetworkID)
if floatingNetworkID == "" {
var err error
floatingNetworkID, err = openstackutil.GetFloatingNetworkID(lbaas.network)
if err != nil {
klog.Warningf("Failed to find floating-network-id for Service %s: %v", serviceName, err)
}
}
}
// apply defaults from CCM config
if floatingNetworkID == "" {
floatingNetworkID = lbaas.opts.FloatingNetworkID
}
if !floatingSubnet.Configured() {
annos := floatingSubnetSpec{}
annos.subnetID = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerFloatingSubnetID, "")
if annos.subnetID == "" {
annos.subnet = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerFloatingSubnet, "")
annos.subnetTags = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerFloatingSubnetTags, "")
}
if annos.Configured() {
floatingSubnet = annos
} else {
floatingSubnet.subnetID = lbaas.opts.FloatingSubnetID
if floatingSubnet.subnetID == "" {
floatingSubnet.subnetTags = lbaas.opts.FloatingSubnetTags
floatingSubnet.subnet = lbaas.opts.FloatingSubnet
}
}
}
// check subnets belongs to network
if floatingNetworkID != "" && floatingSubnet.subnetID != "" {
mc := metrics.NewMetricContext("subnet", "get")
subnet, err := subnets.Get(lbaas.network, floatingSubnet.subnetID).Extract()
if mc.ObserveRequest(err) != nil {
return fmt.Errorf("failed to find subnet %q: %v", floatingSubnet.subnetID, err)
}
if subnet.NetworkID != floatingNetworkID {
return fmt.Errorf("floating IP subnet %q doesn't belong to the network %q", floatingSubnet.subnetID, subnet.NetworkID)
}
}
svcConf.lbPublicNetworkID = floatingNetworkID
if floatingSubnet.Configured() {
klog.V(4).Infof("Using subnet spec %+v for %s", floatingSubnet, serviceName)
svcConf.lbPublicSubnetSpec = &floatingSubnet
} else {
klog.V(4).Infof("no subnet spec found for %s", serviceName)
}
} else {
klog.V(4).Infof("Ensure an internal loadbalancer service.")
}
keepClientIP := getBoolFromServiceAnnotation(service, ServiceAnnotationLoadBalancerXForwardedFor, false)
useProxyProtocol := getBoolFromServiceAnnotation(service, ServiceAnnotationLoadBalancerProxyEnabled, false)
if useProxyProtocol && keepClientIP {
return fmt.Errorf("annotation %s and %s cannot be used together", ServiceAnnotationLoadBalancerProxyEnabled, ServiceAnnotationLoadBalancerXForwardedFor)
}
svcConf.keepClientIP = keepClientIP
svcConf.enableProxyProtocol = useProxyProtocol
if openstackutil.IsOctaviaFeatureSupported(lbaas.lb, openstackutil.OctaviaFeatureTimeout, lbaas.opts.LBProvider) {
svcConf.timeoutClientData = getIntFromServiceAnnotation(service, ServiceAnnotationLoadBalancerTimeoutClientData, 50000)
svcConf.timeoutMemberConnect = getIntFromServiceAnnotation(service, ServiceAnnotationLoadBalancerTimeoutMemberConnect, 5000)
svcConf.timeoutMemberData = getIntFromServiceAnnotation(service, ServiceAnnotationLoadBalancerTimeoutMemberData, 50000)
svcConf.timeoutTCPInspect = getIntFromServiceAnnotation(service, ServiceAnnotationLoadBalancerTimeoutTCPInspect, 0)
}
var listenerAllowedCIDRs []string
sourceRanges, err := GetLoadBalancerSourceRanges(service)
if err != nil {
return fmt.Errorf("failed to get source ranges for loadbalancer service %s: %v", serviceName, err)
}
if openstackutil.IsOctaviaFeatureSupported(lbaas.lb, openstackutil.OctaviaFeatureVIPACL, lbaas.opts.LBProvider) {
klog.V(4).Info("LoadBalancerSourceRanges is suppported")
listenerAllowedCIDRs = sourceRanges.StringSlice()
} else {
klog.Warning("LoadBalancerSourceRanges is ignored")
}
svcConf.allowedCIDR = listenerAllowedCIDRs
if openstackutil.IsOctaviaFeatureSupported(lbaas.lb, openstackutil.OctaviaFeatureFlavors, lbaas.opts.LBProvider) {
svcConf.flavorID = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerFlavorID, lbaas.opts.FlavorID)
}
availabilityZone := getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerAvailabilityZone, lbaas.opts.AvailabilityZone)
if openstackutil.IsOctaviaFeatureSupported(lbaas.lb, openstackutil.OctaviaFeatureAvailabilityZones, lbaas.opts.LBProvider) {
svcConf.availabilityZone = availabilityZone
} else if availabilityZone != "" {
klog.Warning("LoadBalancer Availability Zones aren't supported. Please, upgrade Octavia API to version 2.14 or later (Ussuri release) to use them")
}
svcConf.enableMonitor = getBoolFromServiceAnnotation(service, ServiceAnnotationLoadBalancerEnableHealthMonitor, lbaas.opts.CreateMonitor)
if svcConf.enableMonitor && lbaas.opts.UseOctavia && service.Spec.ExternalTrafficPolicy == corev1.ServiceExternalTrafficPolicyTypeLocal && service.Spec.HealthCheckNodePort > 0 {
svcConf.healthCheckNodePort = int(service.Spec.HealthCheckNodePort)
}
svcConf.healthMonitorDelay = getIntFromServiceAnnotation(service, ServiceAnnotationLoadBalancerHealthMonitorDelay, int(lbaas.opts.MonitorDelay.Duration.Seconds()))
svcConf.healthMonitorTimeout = getIntFromServiceAnnotation(service, ServiceAnnotationLoadBalancerHealthMonitorTimeout, int(lbaas.opts.MonitorTimeout.Duration.Seconds()))
svcConf.healthMonitorMaxRetries = getIntFromServiceAnnotation(service, ServiceAnnotationLoadBalancerHealthMonitorMaxRetries, int(lbaas.opts.MonitorMaxRetries))
return nil
}