Merge "Update loadbalancer CRD with service spec and rely on CRD"
This commit is contained in:
commit
3eeb67d84e
|
@ -99,7 +99,7 @@
|
||||||
vars:
|
vars:
|
||||||
devstack_localrc:
|
devstack_localrc:
|
||||||
DOCKER_CGROUP_DRIVER: "systemd"
|
DOCKER_CGROUP_DRIVER: "systemd"
|
||||||
KURYR_ENABLED_HANDLERS: vif,lb,lbaasspec,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport
|
KURYR_ENABLED_HANDLERS: vif,endpoints,service,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport,kuryrloadbalancer
|
||||||
KURYR_SG_DRIVER: policy
|
KURYR_SG_DRIVER: policy
|
||||||
KURYR_SUBNET_DRIVER: namespace
|
KURYR_SUBNET_DRIVER: namespace
|
||||||
devstack_services:
|
devstack_services:
|
||||||
|
@ -120,7 +120,7 @@
|
||||||
vars:
|
vars:
|
||||||
devstack_localrc:
|
devstack_localrc:
|
||||||
KURYR_SUBNET_DRIVER: namespace
|
KURYR_SUBNET_DRIVER: namespace
|
||||||
KURYR_ENABLED_HANDLERS: vif,lb,lbaasspec,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport
|
KURYR_ENABLED_HANDLERS: vif,endpoints,service,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport,kuryrloadbalancer
|
||||||
KURYR_SG_DRIVER: policy
|
KURYR_SG_DRIVER: policy
|
||||||
KURYR_USE_PORT_POOLS: true
|
KURYR_USE_PORT_POOLS: true
|
||||||
KURYR_POD_VIF_DRIVER: neutron-vif
|
KURYR_POD_VIF_DRIVER: neutron-vif
|
||||||
|
@ -134,7 +134,7 @@
|
||||||
parent: kuryr-kubernetes-tempest-containerized
|
parent: kuryr-kubernetes-tempest-containerized
|
||||||
vars:
|
vars:
|
||||||
devstack_localrc:
|
devstack_localrc:
|
||||||
KURYR_ENABLED_HANDLERS: vif,lb,lbaasspec,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport
|
KURYR_ENABLED_HANDLERS: vif,endpoints,service,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport,kuryrloadbalancer
|
||||||
KURYR_SG_DRIVER: policy
|
KURYR_SG_DRIVER: policy
|
||||||
KURYR_SUBNET_DRIVER: namespace
|
KURYR_SUBNET_DRIVER: namespace
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
KURYR_LB_ALGORITHM: SOURCE_IP_PORT
|
KURYR_LB_ALGORITHM: SOURCE_IP_PORT
|
||||||
KURYR_SUBNET_DRIVER: namespace
|
KURYR_SUBNET_DRIVER: namespace
|
||||||
KURYR_SG_DRIVER: policy
|
KURYR_SG_DRIVER: policy
|
||||||
KURYR_ENABLED_HANDLERS: vif,lb,lbaasspec,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport
|
KURYR_ENABLED_HANDLERS: vif,endpoints,service,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport,kuryrloadbalancer
|
||||||
voting: false
|
voting: false
|
||||||
|
|
||||||
- job:
|
- job:
|
||||||
|
@ -144,7 +144,7 @@
|
||||||
KURYR_ENFORCE_SG_RULES: false
|
KURYR_ENFORCE_SG_RULES: false
|
||||||
KURYR_LB_ALGORITHM: SOURCE_IP_PORT
|
KURYR_LB_ALGORITHM: SOURCE_IP_PORT
|
||||||
KURYR_HYPERKUBE_VERSION: v1.16.0
|
KURYR_HYPERKUBE_VERSION: v1.16.0
|
||||||
KURYR_ENABLED_HANDLERS: vif,lb,lbaasspec,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport
|
KURYR_ENABLED_HANDLERS: vif,endpoints,service,namespace,pod_label,policy,kuryrnetpolicy,kuryrnetwork,kuryrport,kuryrloadbalancer
|
||||||
KURYR_SG_DRIVER: policy
|
KURYR_SG_DRIVER: policy
|
||||||
KURYR_SUBNET_DRIVER: namespace
|
KURYR_SUBNET_DRIVER: namespace
|
||||||
KURYR_K8S_CONTAINERIZED_DEPLOYMENT: true
|
KURYR_K8S_CONTAINERIZED_DEPLOYMENT: true
|
||||||
|
|
|
@ -974,6 +974,7 @@ function update_tempest_conf_file {
|
||||||
iniset $TEMPEST_CONFIG kuryr_kubernetes validate_crd True
|
iniset $TEMPEST_CONFIG kuryr_kubernetes validate_crd True
|
||||||
iniset $TEMPEST_CONFIG kuryr_kubernetes kuryrnetworks True
|
iniset $TEMPEST_CONFIG kuryr_kubernetes kuryrnetworks True
|
||||||
iniset $TEMPEST_CONFIG kuryr_kubernetes kuryrports True
|
iniset $TEMPEST_CONFIG kuryr_kubernetes kuryrports True
|
||||||
|
iniset $TEMPEST_CONFIG kuryr_kubernetes kuryrloadbalancers True
|
||||||
}
|
}
|
||||||
|
|
||||||
source $DEST/kuryr-kubernetes/devstack/lib/kuryr_kubernetes
|
source $DEST/kuryr-kubernetes/devstack/lib/kuryr_kubernetes
|
||||||
|
|
|
@ -43,7 +43,7 @@ KURYR_K8S_API_LB_PORT=${KURYR_K8S_API_LB_PORT:-443}
|
||||||
KURYR_PORT_DEBUG=${KURYR_PORT_DEBUG:-True}
|
KURYR_PORT_DEBUG=${KURYR_PORT_DEBUG:-True}
|
||||||
KURYR_SUBNET_DRIVER=${KURYR_SUBNET_DRIVER:-default}
|
KURYR_SUBNET_DRIVER=${KURYR_SUBNET_DRIVER:-default}
|
||||||
KURYR_SG_DRIVER=${KURYR_SG_DRIVER:-default}
|
KURYR_SG_DRIVER=${KURYR_SG_DRIVER:-default}
|
||||||
KURYR_ENABLED_HANDLERS=${KURYR_ENABLED_HANDLERS:-vif,lb,lbaasspec,kuryrport}
|
KURYR_ENABLED_HANDLERS=${KURYR_ENABLED_HANDLERS:-vif,endpoints,service,kuryrloadbalancer,kuryrport}
|
||||||
|
|
||||||
# OpenShift
|
# OpenShift
|
||||||
OPENSHIFT_BINARY_VERSION=${OPENSHIFT_BINARY_VERSION:-v3.11.0}
|
OPENSHIFT_BINARY_VERSION=${OPENSHIFT_BINARY_VERSION:-v3.11.0}
|
||||||
|
|
|
@ -29,13 +29,6 @@ spec:
|
||||||
properties:
|
properties:
|
||||||
spec:
|
spec:
|
||||||
type: object
|
type: object
|
||||||
required:
|
|
||||||
- ip
|
|
||||||
- ports
|
|
||||||
- project_id
|
|
||||||
- security_groups_ids
|
|
||||||
- subnet_id
|
|
||||||
- type
|
|
||||||
properties:
|
properties:
|
||||||
ip:
|
ip:
|
||||||
type: string
|
type: string
|
||||||
|
@ -46,7 +39,6 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- name
|
|
||||||
- port
|
- port
|
||||||
- protocol
|
- protocol
|
||||||
- targetPort
|
- targetPort
|
||||||
|
@ -69,13 +61,50 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
|
subsets:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
addresses:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
hostname:
|
||||||
|
type: string
|
||||||
|
ip:
|
||||||
|
type: string
|
||||||
|
nodeName:
|
||||||
|
type: string
|
||||||
|
targetRef:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
|
resourceVersion:
|
||||||
|
type: string
|
||||||
|
uid:
|
||||||
|
type: string
|
||||||
|
ports:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
port:
|
||||||
|
type: integer
|
||||||
|
protocol:
|
||||||
|
type: string
|
||||||
status:
|
status:
|
||||||
type: object
|
type: object
|
||||||
required:
|
|
||||||
- listeners
|
|
||||||
- loadbalancer
|
|
||||||
- members
|
|
||||||
- pools
|
|
||||||
properties:
|
properties:
|
||||||
listeners:
|
listeners:
|
||||||
type: array
|
type: array
|
||||||
|
|
|
@ -66,6 +66,8 @@ K8S_ANNOTATION_NEUTRON_PORT = 'neutron_id'
|
||||||
|
|
||||||
POD_FINALIZER = KURYR_FQDN + '/pod-finalizer'
|
POD_FINALIZER = KURYR_FQDN + '/pod-finalizer'
|
||||||
KURYRNETWORK_FINALIZER = 'kuryrnetwork.finalizers.kuryr.openstack.org'
|
KURYRNETWORK_FINALIZER = 'kuryrnetwork.finalizers.kuryr.openstack.org'
|
||||||
|
KURYRLB_FINALIZER = 'kuryr.openstack.org/kuryrloadbalancer-finalizers'
|
||||||
|
SERVICE_FINALIZER = 'kuryr.openstack.org/service-finalizer'
|
||||||
|
|
||||||
KURYRPORT_FINALIZER = KURYR_FQDN + '/kuryrport-finalizer'
|
KURYRPORT_FINALIZER = KURYR_FQDN + '/kuryrport-finalizer'
|
||||||
KURYRPORT_LABEL = KURYR_FQDN + '/nodeName'
|
KURYRPORT_LABEL = KURYR_FQDN + '/nodeName'
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
from kuryr_kubernetes import config
|
from kuryr_kubernetes import config
|
||||||
from kuryr_kubernetes.controller.drivers import base
|
from kuryr_kubernetes.controller.drivers import base
|
||||||
from kuryr_kubernetes.controller.drivers import public_ip
|
from kuryr_kubernetes.controller.drivers import public_ip
|
||||||
from kuryr_kubernetes.objects import lbaas as obj_lbaas
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
@ -50,10 +49,11 @@ class FloatingIpServicePubIPDriver(base.ServicePubIpDriver):
|
||||||
res_id = self._drv_pub_ip.is_ip_available(user_specified_ip,
|
res_id = self._drv_pub_ip.is_ip_available(user_specified_ip,
|
||||||
port_id_to_be_associated)
|
port_id_to_be_associated)
|
||||||
if res_id:
|
if res_id:
|
||||||
service_pub_ip_info = (obj_lbaas.LBaaSPubIp(
|
service_pub_ip_info = {
|
||||||
ip_id=res_id,
|
'ip_id': res_id,
|
||||||
ip_addr=str(user_specified_ip),
|
'ip_addr': str(user_specified_ip),
|
||||||
alloc_method='user'))
|
'alloc_method': 'user'
|
||||||
|
}
|
||||||
|
|
||||||
return service_pub_ip_info
|
return service_pub_ip_info
|
||||||
else:
|
else:
|
||||||
|
@ -78,32 +78,34 @@ class FloatingIpServicePubIPDriver(base.ServicePubIpDriver):
|
||||||
LOG.exception("Failed to allocate public IP - net_id:%s",
|
LOG.exception("Failed to allocate public IP - net_id:%s",
|
||||||
public_network_id)
|
public_network_id)
|
||||||
return None
|
return None
|
||||||
service_pub_ip_info = obj_lbaas.LBaaSPubIp(ip_id=res_id,
|
service_pub_ip_info = {
|
||||||
ip_addr=alloc_ip_addr,
|
'ip_id': res_id,
|
||||||
alloc_method='pool')
|
'ip_addr': alloc_ip_addr,
|
||||||
|
'alloc_method': 'pool'
|
||||||
|
}
|
||||||
|
|
||||||
return service_pub_ip_info
|
return service_pub_ip_info
|
||||||
|
|
||||||
def release_pub_ip(self, service_pub_ip_info):
|
def release_pub_ip(self, service_pub_ip_info):
|
||||||
if not service_pub_ip_info:
|
if not service_pub_ip_info:
|
||||||
return True
|
return True
|
||||||
if service_pub_ip_info.alloc_method == 'pool':
|
if service_pub_ip_info['alloc_method'] == 'pool':
|
||||||
retcode = self._drv_pub_ip.free_ip(service_pub_ip_info.ip_id)
|
retcode = self._drv_pub_ip.free_ip(service_pub_ip_info['ip_id'])
|
||||||
if not retcode:
|
if not retcode:
|
||||||
LOG.error("Failed to delete public_ip_id =%s !",
|
LOG.error("Failed to delete public_ip_id =%s !",
|
||||||
service_pub_ip_info.ip_id)
|
service_pub_ip_info['ip_id'])
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def associate_pub_ip(self, service_pub_ip_info, vip_port_id):
|
def associate_pub_ip(self, service_pub_ip_info, vip_port_id):
|
||||||
if (not service_pub_ip_info or
|
if (not service_pub_ip_info or
|
||||||
not vip_port_id or
|
not vip_port_id or
|
||||||
not service_pub_ip_info.ip_id):
|
not service_pub_ip_info['ip_id']):
|
||||||
return
|
return
|
||||||
self._drv_pub_ip.associate(
|
self._drv_pub_ip.associate(
|
||||||
service_pub_ip_info.ip_id, vip_port_id)
|
service_pub_ip_info['ip_id'], vip_port_id)
|
||||||
|
|
||||||
def disassociate_pub_ip(self, service_pub_ip_info):
|
def disassociate_pub_ip(self, service_pub_ip_info):
|
||||||
if not service_pub_ip_info or not service_pub_ip_info.ip_id:
|
if not service_pub_ip_info or not service_pub_ip_info['ip_id']:
|
||||||
return
|
return
|
||||||
self._drv_pub_ip.disassociate(service_pub_ip_info.ip_id)
|
self._drv_pub_ip.disassociate(service_pub_ip_info['ip_id'])
|
||||||
|
|
|
@ -27,7 +27,6 @@ from kuryr_kubernetes import config
|
||||||
from kuryr_kubernetes import constants as k_const
|
from kuryr_kubernetes import constants as k_const
|
||||||
from kuryr_kubernetes.controller.drivers import base
|
from kuryr_kubernetes.controller.drivers import base
|
||||||
from kuryr_kubernetes import exceptions as k_exc
|
from kuryr_kubernetes import exceptions as k_exc
|
||||||
from kuryr_kubernetes.objects import lbaas as obj_lbaas
|
|
||||||
from kuryr_kubernetes import utils
|
from kuryr_kubernetes import utils
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
@ -112,7 +111,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
return "%s/%s" % (namespace, svc_name)
|
return "%s/%s" % (namespace, svc_name)
|
||||||
|
|
||||||
def get_loadbalancer_pool_name(self, loadbalancer, namespace, svc_name):
|
def get_loadbalancer_pool_name(self, loadbalancer, namespace, svc_name):
|
||||||
return "%s/%s/%s" % (loadbalancer.name, namespace, svc_name)
|
return "%s/%s/%s" % (loadbalancer['name'], namespace, svc_name)
|
||||||
|
|
||||||
def add_tags(self, resource, req):
|
def add_tags(self, resource, req):
|
||||||
if CONF.neutron_defaults.resource_tags:
|
if CONF.neutron_defaults.resource_tags:
|
||||||
|
@ -126,9 +125,14 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
def ensure_loadbalancer(self, name, project_id, subnet_id, ip,
|
def ensure_loadbalancer(self, name, project_id, subnet_id, ip,
|
||||||
security_groups_ids=None, service_type=None,
|
security_groups_ids=None, service_type=None,
|
||||||
provider=None):
|
provider=None):
|
||||||
request = obj_lbaas.LBaaSLoadBalancer(
|
request = {
|
||||||
name=name, project_id=project_id, subnet_id=subnet_id, ip=ip,
|
'name': name,
|
||||||
security_groups=security_groups_ids, provider=provider)
|
'project_id': project_id,
|
||||||
|
'subnet_id': subnet_id,
|
||||||
|
'ip': ip,
|
||||||
|
'security_groups': security_groups_ids,
|
||||||
|
'provider': provider
|
||||||
|
}
|
||||||
response = self._ensure(self._create_loadbalancer,
|
response = self._ensure(self._create_loadbalancer,
|
||||||
self._find_loadbalancer, request)
|
self._find_loadbalancer, request)
|
||||||
if not response:
|
if not response:
|
||||||
|
@ -146,9 +150,8 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
loadbalancer,
|
loadbalancer,
|
||||||
loadbalancer,
|
loadbalancer,
|
||||||
lbaas.delete_load_balancer,
|
lbaas.delete_load_balancer,
|
||||||
loadbalancer.id,
|
loadbalancer['id'],
|
||||||
cascade=True)
|
cascade=True)
|
||||||
|
|
||||||
self._wait_for_deletion(loadbalancer, _ACTIVATION_TIMEOUT)
|
self._wait_for_deletion(loadbalancer, _ACTIVATION_TIMEOUT)
|
||||||
|
|
||||||
def _create_listeners_acls(self, loadbalancer, port, target_port,
|
def _create_listeners_acls(self, loadbalancer, port, target_port,
|
||||||
|
@ -160,7 +163,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
if new_sgs:
|
if new_sgs:
|
||||||
sgs = new_sgs
|
sgs = new_sgs
|
||||||
else:
|
else:
|
||||||
sgs = loadbalancer.security_groups
|
sgs = loadbalancer['security_groups']
|
||||||
|
|
||||||
# Check if Network Policy allows listener on the pods
|
# Check if Network Policy allows listener on the pods
|
||||||
for sg in sgs:
|
for sg in sgs:
|
||||||
|
@ -210,7 +213,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
if vip_port:
|
if vip_port:
|
||||||
lb_sg = vip_port.security_group_ids[0]
|
lb_sg = vip_port.security_group_ids[0]
|
||||||
else:
|
else:
|
||||||
LOG.debug("Skipping sg update for lb %s", loadbalancer.name)
|
LOG.debug("Skipping sg update for lb %s", loadbalancer['name'])
|
||||||
return
|
return
|
||||||
|
|
||||||
# NOTE (maysams) It might happen that the update of LBaaS SG
|
# NOTE (maysams) It might happen that the update of LBaaS SG
|
||||||
|
@ -225,14 +228,14 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
return
|
return
|
||||||
|
|
||||||
lbaas_sg_rules = os_net.security_group_rules(
|
lbaas_sg_rules = os_net.security_group_rules(
|
||||||
security_group_id=lb_sg, project_id=loadbalancer.project_id)
|
security_group_id=lb_sg, project_id=loadbalancer['project_id'])
|
||||||
all_pod_rules = []
|
all_pod_rules = []
|
||||||
add_default_rules = False
|
add_default_rules = False
|
||||||
|
|
||||||
if new_sgs:
|
if new_sgs:
|
||||||
sgs = new_sgs
|
sgs = new_sgs
|
||||||
else:
|
else:
|
||||||
sgs = loadbalancer.security_groups
|
sgs = loadbalancer['security_groups']
|
||||||
|
|
||||||
sg_rule_ethertype = k_const.IPv4
|
sg_rule_ethertype = k_const.IPv4
|
||||||
if utils.get_service_subnet_version() == k_const.IP_VERSION_6:
|
if utils.get_service_subnet_version() == k_const.IP_VERSION_6:
|
||||||
|
@ -325,12 +328,14 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
|
|
||||||
def ensure_listener(self, loadbalancer, protocol, port,
|
def ensure_listener(self, loadbalancer, protocol, port,
|
||||||
service_type='ClusterIP'):
|
service_type='ClusterIP'):
|
||||||
name = "%s:%s:%s" % (loadbalancer.name, protocol, port)
|
name = "%s:%s:%s" % (loadbalancer['name'], protocol, port)
|
||||||
listener = obj_lbaas.LBaaSListener(name=name,
|
listener = {
|
||||||
project_id=loadbalancer.project_id,
|
'name': name,
|
||||||
loadbalancer_id=loadbalancer.id,
|
'project_id': loadbalancer['project_id'],
|
||||||
protocol=protocol,
|
'loadbalancer_id': loadbalancer['id'],
|
||||||
port=port)
|
'protocol': protocol,
|
||||||
|
'port': port
|
||||||
|
}
|
||||||
try:
|
try:
|
||||||
result = self._ensure_provisioned(
|
result = self._ensure_provisioned(
|
||||||
loadbalancer, listener, self._create_listener,
|
loadbalancer, listener, self._create_listener,
|
||||||
|
@ -348,7 +353,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
os_net = clients.get_network_client()
|
os_net = clients.get_network_client()
|
||||||
vip_port = self._get_vip_port(loadbalancer)
|
vip_port = self._get_vip_port(loadbalancer)
|
||||||
os_net.update_port(vip_port.id, security_groups=[])
|
os_net.update_port(vip_port.id, security_groups=[])
|
||||||
loadbalancer.security_groups = []
|
loadbalancer['security_groups'] = []
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -357,7 +362,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
self._release(loadbalancer, listener,
|
self._release(loadbalancer, listener,
|
||||||
lbaas.delete_listener,
|
lbaas.delete_listener,
|
||||||
listener.id)
|
listener['id'])
|
||||||
|
|
||||||
# NOTE(maysams): since lbs created with ovn-octavia provider
|
# NOTE(maysams): since lbs created with ovn-octavia provider
|
||||||
# does not have a sg in place, only need to delete sg rules
|
# does not have a sg in place, only need to delete sg rules
|
||||||
|
@ -367,19 +372,22 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
sg_id = self._get_vip_port(loadbalancer).security_group_ids[0]
|
sg_id = self._get_vip_port(loadbalancer).security_group_ids[0]
|
||||||
if sg_id:
|
if sg_id:
|
||||||
rules = os_net.security_group_rules(security_group_id=sg_id,
|
rules = os_net.security_group_rules(security_group_id=sg_id,
|
||||||
description=listener.name)
|
description=listener[
|
||||||
|
'name'])
|
||||||
try:
|
try:
|
||||||
os_net.delete_security_group_rule(next(rules).id)
|
os_net.delete_security_group_rule(next(rules).id)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
LOG.warning('Cannot find SG rule for %s (%s) listener.',
|
LOG.warning('Cannot find SG rule for %s (%s) listener.',
|
||||||
listener.id, listener.name)
|
listener['id'], listener['name'])
|
||||||
|
|
||||||
def ensure_pool(self, loadbalancer, listener):
|
def ensure_pool(self, loadbalancer, listener):
|
||||||
pool = obj_lbaas.LBaaSPool(name=listener.name,
|
pool = {
|
||||||
project_id=loadbalancer.project_id,
|
'name': listener['name'],
|
||||||
loadbalancer_id=loadbalancer.id,
|
'project_id': loadbalancer['project_id'],
|
||||||
listener_id=listener.id,
|
'loadbalancer_id': loadbalancer['id'],
|
||||||
protocol=listener.protocol)
|
'listener_id': listener['id'],
|
||||||
|
'protocol': listener['protocol']
|
||||||
|
}
|
||||||
return self._ensure_provisioned(loadbalancer, pool,
|
return self._ensure_provisioned(loadbalancer, pool,
|
||||||
self._create_pool,
|
self._create_pool,
|
||||||
self._find_pool)
|
self._find_pool)
|
||||||
|
@ -388,30 +396,34 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
svc_name, protocol):
|
svc_name, protocol):
|
||||||
name = self.get_loadbalancer_pool_name(loadbalancer,
|
name = self.get_loadbalancer_pool_name(loadbalancer,
|
||||||
namespace, svc_name)
|
namespace, svc_name)
|
||||||
pool = obj_lbaas.LBaaSPool(name=name,
|
pool = {
|
||||||
project_id=loadbalancer.project_id,
|
'name': name,
|
||||||
loadbalancer_id=loadbalancer.id,
|
'project_id': loadbalancer['project_id'],
|
||||||
listener_id=None,
|
'loadbalancer_id': loadbalancer['id'],
|
||||||
protocol=protocol)
|
'listener_id': None,
|
||||||
|
'protocol': protocol
|
||||||
|
}
|
||||||
return self._ensure_provisioned(loadbalancer, pool,
|
return self._ensure_provisioned(loadbalancer, pool,
|
||||||
self._create_pool,
|
self._create_pool,
|
||||||
self._find_pool_by_name)
|
self._find_pool_by_name)
|
||||||
|
|
||||||
def release_pool(self, loadbalancer, pool):
|
def release_pool(self, loadbalancer, pool):
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
self._release(loadbalancer, pool, lbaas.delete_pool, pool.id)
|
self._release(loadbalancer, pool, lbaas.delete_pool, pool['id'])
|
||||||
|
|
||||||
def ensure_member(self, loadbalancer, pool,
|
def ensure_member(self, loadbalancer, pool,
|
||||||
subnet_id, ip, port, target_ref_namespace,
|
subnet_id, ip, port, target_ref_namespace,
|
||||||
target_ref_name, listener_port=None):
|
target_ref_name, listener_port=None):
|
||||||
name = ("%s/%s" % (target_ref_namespace, target_ref_name))
|
name = ("%s/%s" % (target_ref_namespace, target_ref_name))
|
||||||
name += ":%s" % port
|
name += ":%s" % port
|
||||||
member = obj_lbaas.LBaaSMember(name=name,
|
member = {
|
||||||
project_id=loadbalancer.project_id,
|
'name': name,
|
||||||
pool_id=pool.id,
|
'project_id': loadbalancer['project_id'],
|
||||||
subnet_id=subnet_id,
|
'pool_id': pool['id'],
|
||||||
ip=ip,
|
'subnet_id': subnet_id,
|
||||||
port=port)
|
'ip': ip,
|
||||||
|
'port': port
|
||||||
|
}
|
||||||
result = self._ensure_provisioned(loadbalancer, member,
|
result = self._ensure_provisioned(loadbalancer, member,
|
||||||
self._create_member,
|
self._create_member,
|
||||||
self._find_member)
|
self._find_member)
|
||||||
|
@ -421,9 +433,9 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
CONF.kubernetes.service_security_groups_driver == 'policy')
|
CONF.kubernetes.service_security_groups_driver == 'policy')
|
||||||
if (network_policy and CONF.octavia_defaults.enforce_sg_rules and
|
if (network_policy and CONF.octavia_defaults.enforce_sg_rules and
|
||||||
listener_port):
|
listener_port):
|
||||||
protocol = pool.protocol
|
protocol = pool['protocol']
|
||||||
sg_rule_name = pool.name
|
sg_rule_name = pool['name']
|
||||||
listener_id = pool.listener_id
|
listener_id = pool['listener_id']
|
||||||
self._apply_members_security_groups(loadbalancer, listener_port,
|
self._apply_members_security_groups(loadbalancer, listener_port,
|
||||||
port, protocol, sg_rule_name,
|
port, protocol, sg_rule_name,
|
||||||
listener_id)
|
listener_id)
|
||||||
|
@ -431,14 +443,14 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
|
|
||||||
def release_member(self, loadbalancer, member):
|
def release_member(self, loadbalancer, member):
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
self._release(loadbalancer, member, lbaas.delete_member, member.id,
|
self._release(loadbalancer, member, lbaas.delete_member, member['id'],
|
||||||
member.pool_id)
|
member['pool_id'])
|
||||||
|
|
||||||
def _get_vip_port(self, loadbalancer):
|
def _get_vip_port(self, loadbalancer):
|
||||||
os_net = clients.get_network_client()
|
os_net = clients.get_network_client()
|
||||||
try:
|
try:
|
||||||
fixed_ips = ['subnet_id=%s' % str(loadbalancer.subnet_id),
|
fixed_ips = ['subnet_id=%s' % str(loadbalancer['subnet_id']),
|
||||||
'ip_address=%s' % str(loadbalancer.ip)]
|
'ip_address=%s' % str(loadbalancer['ip'])]
|
||||||
ports = os_net.ports(fixed_ips=fixed_ips)
|
ports = os_net.ports(fixed_ips=fixed_ips)
|
||||||
except os_exc.SDKException:
|
except os_exc.SDKException:
|
||||||
LOG.error("Port with fixed ips %s not found!", fixed_ips)
|
LOG.error("Port with fixed ips %s not found!", fixed_ips)
|
||||||
|
@ -451,43 +463,43 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
|
|
||||||
def _create_loadbalancer(self, loadbalancer):
|
def _create_loadbalancer(self, loadbalancer):
|
||||||
request = {
|
request = {
|
||||||
'name': loadbalancer.name,
|
'name': loadbalancer['name'],
|
||||||
'project_id': loadbalancer.project_id,
|
'project_id': loadbalancer['project_id'],
|
||||||
'vip_address': str(loadbalancer.ip),
|
'vip_address': str(loadbalancer['ip']),
|
||||||
'vip_subnet_id': loadbalancer.subnet_id,
|
'vip_subnet_id': loadbalancer['subnet_id'],
|
||||||
}
|
}
|
||||||
|
|
||||||
if loadbalancer.provider is not None:
|
if loadbalancer['provider'] is not None:
|
||||||
request['provider'] = loadbalancer.provider
|
request['provider'] = loadbalancer['provider']
|
||||||
|
|
||||||
self.add_tags('loadbalancer', request)
|
self.add_tags('loadbalancer', request)
|
||||||
|
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
response = lbaas.create_load_balancer(**request)
|
response = lbaas.create_load_balancer(**request)
|
||||||
loadbalancer.id = response.id
|
loadbalancer['id'] = response.id
|
||||||
loadbalancer.port_id = self._get_vip_port(loadbalancer).id
|
loadbalancer['port_id'] = self._get_vip_port(loadbalancer).id
|
||||||
if (loadbalancer.provider is not None and
|
if (loadbalancer['provider'] is not None and
|
||||||
loadbalancer.provider != response.provider):
|
loadbalancer['provider'] != response.provider):
|
||||||
LOG.error("Request provider(%s) != Response provider(%s)",
|
LOG.error("Request provider(%s) != Response provider(%s)",
|
||||||
loadbalancer.provider, response.provider)
|
loadbalancer['provider'], response.provider)
|
||||||
return None
|
return None
|
||||||
loadbalancer.provider = response.provider
|
loadbalancer['provider'] = response.provider
|
||||||
return loadbalancer
|
return loadbalancer
|
||||||
|
|
||||||
def _find_loadbalancer(self, loadbalancer):
|
def _find_loadbalancer(self, loadbalancer):
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
response = lbaas.load_balancers(
|
response = lbaas.load_balancers(
|
||||||
name=loadbalancer.name,
|
name=loadbalancer['name'],
|
||||||
project_id=loadbalancer.project_id,
|
project_id=loadbalancer['project_id'],
|
||||||
vip_address=str(loadbalancer.ip),
|
vip_address=str(loadbalancer['ip']),
|
||||||
vip_subnet_id=loadbalancer.subnet_id,
|
vip_subnet_id=loadbalancer['subnet_id'],
|
||||||
provider=loadbalancer.provider)
|
provider=loadbalancer['provider'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os_lb = next(response) # openstacksdk returns a generator
|
os_lb = next(response) # openstacksdk returns a generator
|
||||||
loadbalancer.id = os_lb.id
|
loadbalancer['id'] = os_lb.id
|
||||||
loadbalancer.port_id = self._get_vip_port(loadbalancer).id
|
loadbalancer['port_id'] = self._get_vip_port(loadbalancer).id
|
||||||
loadbalancer.provider = os_lb.provider
|
loadbalancer['provider'] = os_lb.provider
|
||||||
if os_lb.provisioning_status == 'ERROR':
|
if os_lb.provisioning_status == 'ERROR':
|
||||||
self.release_loadbalancer(loadbalancer)
|
self.release_loadbalancer(loadbalancer)
|
||||||
return None
|
return None
|
||||||
|
@ -498,16 +510,16 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
|
|
||||||
def _create_listener(self, listener):
|
def _create_listener(self, listener):
|
||||||
request = {
|
request = {
|
||||||
'name': listener.name,
|
'name': listener['name'],
|
||||||
'project_id': listener.project_id,
|
'project_id': listener['project_id'],
|
||||||
'loadbalancer_id': listener.loadbalancer_id,
|
'loadbalancer_id': listener['loadbalancer_id'],
|
||||||
'protocol': listener.protocol,
|
'protocol': listener['protocol'],
|
||||||
'protocol_port': listener.port,
|
'protocol_port': listener['port'],
|
||||||
}
|
}
|
||||||
self.add_tags('listener', request)
|
self.add_tags('listener', request)
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
response = lbaas.create_listener(**request)
|
response = lbaas.create_listener(**request)
|
||||||
listener.id = response.id
|
listener['id'] = response.id
|
||||||
return listener
|
return listener
|
||||||
|
|
||||||
def _update_listener_acls(self, loadbalancer, listener_id, allowed_cidrs):
|
def _update_listener_acls(self, loadbalancer, listener_id, allowed_cidrs):
|
||||||
|
@ -538,15 +550,15 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
def _find_listener(self, listener, loadbalancer):
|
def _find_listener(self, listener, loadbalancer):
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
response = lbaas.listeners(
|
response = lbaas.listeners(
|
||||||
name=listener.name,
|
name=listener['name'],
|
||||||
project_id=listener.project_id,
|
project_id=listener['project_id'],
|
||||||
load_balancer_id=listener.loadbalancer_id,
|
load_balancer_id=listener['loadbalancer_id'],
|
||||||
protocol=listener.protocol,
|
protocol=listener['protocol'],
|
||||||
protocol_port=listener.port)
|
protocol_port=listener['port'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os_listener = next(response)
|
os_listener = next(response)
|
||||||
listener.id = os_listener.id
|
listener['id'] = os_listener.id
|
||||||
if os_listener.provisioning_status == 'ERROR':
|
if os_listener.provisioning_status == 'ERROR':
|
||||||
LOG.debug("Releasing listener %s", os_listener.id)
|
LOG.debug("Releasing listener %s", os_listener.id)
|
||||||
self.release_listener(loadbalancer, listener)
|
self.release_listener(loadbalancer, listener)
|
||||||
|
@ -560,34 +572,34 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
# TODO(ivc): make lb_algorithm configurable
|
# TODO(ivc): make lb_algorithm configurable
|
||||||
lb_algorithm = CONF.octavia_defaults.lb_algorithm
|
lb_algorithm = CONF.octavia_defaults.lb_algorithm
|
||||||
request = {
|
request = {
|
||||||
'name': pool.name,
|
'name': pool['name'],
|
||||||
'project_id': pool.project_id,
|
'project_id': pool['project_id'],
|
||||||
'listener_id': pool.listener_id,
|
'listener_id': pool['listener_id'],
|
||||||
'loadbalancer_id': pool.loadbalancer_id,
|
'loadbalancer_id': pool['loadbalancer_id'],
|
||||||
'protocol': pool.protocol,
|
'protocol': pool['protocol'],
|
||||||
'lb_algorithm': lb_algorithm,
|
'lb_algorithm': lb_algorithm,
|
||||||
}
|
}
|
||||||
self.add_tags('pool', request)
|
self.add_tags('pool', request)
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
response = lbaas.create_pool(**request)
|
response = lbaas.create_pool(**request)
|
||||||
pool.id = response.id
|
pool['id'] = response.id
|
||||||
return pool
|
return pool
|
||||||
|
|
||||||
def _find_pool(self, pool, loadbalancer, by_listener=True):
|
def _find_pool(self, pool, loadbalancer, by_listener=True):
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
response = lbaas.pools(
|
response = lbaas.pools(
|
||||||
name=pool.name,
|
name=pool['name'],
|
||||||
project_id=pool.project_id,
|
project_id=pool['project_id'],
|
||||||
loadbalancer_id=pool.loadbalancer_id,
|
loadbalancer_id=pool['loadbalancer_id'],
|
||||||
protocol=pool.protocol)
|
protocol=pool['protocol'])
|
||||||
|
# TODO(scavnic) check response
|
||||||
try:
|
try:
|
||||||
if by_listener:
|
if by_listener:
|
||||||
pools = [p for p in response if pool.listener_id
|
pools = [p for p in response if pool['listener_id']
|
||||||
in {listener['id'] for listener in p.listeners}]
|
in {listener['id'] for listener in p.listeners}]
|
||||||
else:
|
else:
|
||||||
pools = [p for p in response if pool.name == p.name]
|
pools = [p for p in response if pool.name == p.name]
|
||||||
pool.id = pools[0].id
|
pool['id'] = pools[0].id
|
||||||
if pools[0].provisioning_status == 'ERROR':
|
if pools[0].provisioning_status == 'ERROR':
|
||||||
LOG.debug("Releasing pool %s", pool.id)
|
LOG.debug("Releasing pool %s", pool.id)
|
||||||
self.release_pool(loadbalancer, pool)
|
self.release_pool(loadbalancer, pool)
|
||||||
|
@ -601,31 +613,31 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
|
|
||||||
def _create_member(self, member):
|
def _create_member(self, member):
|
||||||
request = {
|
request = {
|
||||||
'name': member.name,
|
'name': member['name'],
|
||||||
'project_id': member.project_id,
|
'project_id': member['project_id'],
|
||||||
'subnet_id': member.subnet_id,
|
'subnet_id': member['subnet_id'],
|
||||||
'address': str(member.ip),
|
'address': str(member['ip']),
|
||||||
'protocol_port': member.port,
|
'protocol_port': member['port'],
|
||||||
}
|
}
|
||||||
self.add_tags('member', request)
|
self.add_tags('member', request)
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
response = lbaas.create_member(member.pool_id, **request)
|
response = lbaas.create_member(member['pool_id'], **request)
|
||||||
member.id = response.id
|
member['id'] = response.id
|
||||||
return member
|
return member
|
||||||
|
|
||||||
def _find_member(self, member, loadbalancer):
|
def _find_member(self, member, loadbalancer):
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
response = lbaas.members(
|
response = lbaas.members(
|
||||||
member.pool_id,
|
member['pool_id'],
|
||||||
name=member.name,
|
name=member['name'],
|
||||||
project_id=member.project_id,
|
project_id=member['project_id'],
|
||||||
subnet_id=member.subnet_id,
|
subnet_id=member['subnet_id'],
|
||||||
address=member.ip,
|
address=member['ip'],
|
||||||
protocol_port=member.port)
|
protocol_port=member['port'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os_members = next(response)
|
os_members = next(response)
|
||||||
member.id = os_members.id
|
member['id'] = os_members.id
|
||||||
if os_members.provisioning_status == 'ERROR':
|
if os_members.provisioning_status == 'ERROR':
|
||||||
LOG.debug("Releasing Member %s", os_members.id)
|
LOG.debug("Releasing Member %s", os_members.id)
|
||||||
self.release_member(loadbalancer, member)
|
self.release_member(loadbalancer, member)
|
||||||
|
@ -683,7 +695,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
lbaas = clients.get_loadbalancer_client()
|
lbaas = clients.get_loadbalancer_client()
|
||||||
|
|
||||||
for remaining in self._provisioning_timer(timeout, interval):
|
for remaining in self._provisioning_timer(timeout, interval):
|
||||||
response = lbaas.get_load_balancer(loadbalancer.id)
|
response = lbaas.get_load_balancer(loadbalancer['id'])
|
||||||
status = response.provisioning_status
|
status = response.provisioning_status
|
||||||
if status == 'ACTIVE':
|
if status == 'ACTIVE':
|
||||||
LOG.debug("Provisioning complete for %(lb)s", {
|
LOG.debug("Provisioning complete for %(lb)s", {
|
||||||
|
@ -691,7 +703,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
return
|
return
|
||||||
elif status == 'ERROR':
|
elif status == 'ERROR':
|
||||||
LOG.debug("Releasing loadbalancer %s with error status",
|
LOG.debug("Releasing loadbalancer %s with error status",
|
||||||
loadbalancer.id)
|
loadbalancer['id'])
|
||||||
self.release_loadbalancer(loadbalancer)
|
self.release_loadbalancer(loadbalancer)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
@ -708,7 +720,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
|
|
||||||
for remaining in self._provisioning_timer(timeout, interval):
|
for remaining in self._provisioning_timer(timeout, interval):
|
||||||
try:
|
try:
|
||||||
lbaas.get_load_balancer(loadbalancer.id)
|
lbaas.get_load_balancer(loadbalancer['id'])
|
||||||
except os_exc.NotFoundException:
|
except os_exc.NotFoundException:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -753,7 +765,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
|
||||||
|
|
||||||
utils.set_lbaas_state(endpoint, lbaas)
|
utils.set_lbaas_state(endpoint, lbaas)
|
||||||
|
|
||||||
lsnr_ids = {(listener.protocol, listener.port): listener.id
|
lsnr_ids = {(listener['protocol'], listener['port']): listener['id']
|
||||||
for listener in lbaas.listeners}
|
for listener in lbaas.listeners}
|
||||||
|
|
||||||
for port in svc_ports:
|
for port in svc_ports:
|
||||||
|
|
|
@ -13,18 +13,13 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import eventlet
|
|
||||||
import time
|
|
||||||
|
|
||||||
from kuryr.lib._i18n import _
|
from kuryr.lib._i18n import _
|
||||||
from openstack import exceptions as os_exc
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from kuryr_kubernetes import clients
|
from kuryr_kubernetes import clients
|
||||||
from kuryr_kubernetes import config
|
from kuryr_kubernetes import config
|
||||||
from kuryr_kubernetes import constants as k_const
|
from kuryr_kubernetes import constants as k_const
|
||||||
from kuryr_kubernetes.controller.drivers import base as drv_base
|
from kuryr_kubernetes.controller.drivers import base as drv_base
|
||||||
from kuryr_kubernetes.controller.drivers import utils as driver_utils
|
|
||||||
from kuryr_kubernetes import exceptions as k_exc
|
from kuryr_kubernetes import exceptions as k_exc
|
||||||
from kuryr_kubernetes.handlers import k8s_base
|
from kuryr_kubernetes.handlers import k8s_base
|
||||||
from kuryr_kubernetes.objects import lbaas as obj_lbaas
|
from kuryr_kubernetes.objects import lbaas as obj_lbaas
|
||||||
|
@ -35,10 +30,10 @@ LOG = logging.getLogger(__name__)
|
||||||
SUPPORTED_SERVICE_TYPES = ('ClusterIP', 'LoadBalancer')
|
SUPPORTED_SERVICE_TYPES = ('ClusterIP', 'LoadBalancer')
|
||||||
|
|
||||||
|
|
||||||
class LBaaSSpecHandler(k8s_base.ResourceEventHandler):
|
class ServiceHandler(k8s_base.ResourceEventHandler):
|
||||||
"""LBaaSSpecHandler handles K8s Service events.
|
"""ServiceHandler handles K8s Service events.
|
||||||
|
|
||||||
LBaaSSpecHandler handles K8s Service events and updates related Endpoints
|
ServiceHandler handles K8s Service events and updates related Endpoints
|
||||||
with LBaaSServiceSpec when necessary.
|
with LBaaSServiceSpec when necessary.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -46,14 +41,12 @@ class LBaaSSpecHandler(k8s_base.ResourceEventHandler):
|
||||||
OBJECT_WATCH_PATH = "%s/%s" % (k_const.K8S_API_BASE, "services")
|
OBJECT_WATCH_PATH = "%s/%s" % (k_const.K8S_API_BASE, "services")
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(LBaaSSpecHandler, self).__init__()
|
super(ServiceHandler, self).__init__()
|
||||||
self._drv_project = drv_base.ServiceProjectDriver.get_instance()
|
self._drv_project = drv_base.ServiceProjectDriver.get_instance()
|
||||||
self._drv_subnets = drv_base.ServiceSubnetsDriver.get_instance()
|
self._drv_subnets = drv_base.ServiceSubnetsDriver.get_instance()
|
||||||
self._drv_sg = drv_base.ServiceSecurityGroupsDriver.get_instance()
|
self._drv_sg = drv_base.ServiceSecurityGroupsDriver.get_instance()
|
||||||
|
|
||||||
def on_present(self, service):
|
def on_present(self, service):
|
||||||
lbaas_spec = utils.get_lbaas_spec(service)
|
|
||||||
|
|
||||||
if self._should_ignore(service):
|
if self._should_ignore(service):
|
||||||
LOG.debug("Skipping Kubernetes service %s of an unsupported kind "
|
LOG.debug("Skipping Kubernetes service %s of an unsupported kind "
|
||||||
"or without a selector as Kubernetes does not create "
|
"or without a selector as Kubernetes does not create "
|
||||||
|
@ -61,9 +54,18 @@ class LBaaSSpecHandler(k8s_base.ResourceEventHandler):
|
||||||
service['metadata']['name'])
|
service['metadata']['name'])
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._has_lbaas_spec_changes(service, lbaas_spec):
|
k8s = clients.get_kubernetes_client()
|
||||||
lbaas_spec = self._generate_lbaas_spec(service)
|
loadbalancer_crd = k8s.get_loadbalancer_crd(service)
|
||||||
utils.set_lbaas_spec(service, lbaas_spec)
|
try:
|
||||||
|
self._patch_service_finalizer(service)
|
||||||
|
except k_exc.K8sClientException as ex:
|
||||||
|
LOG.exception("Failed to set service finalizer: %s", ex)
|
||||||
|
raise
|
||||||
|
|
||||||
|
if loadbalancer_crd is None:
|
||||||
|
loadbalancer_crd = self.create_crd_spec(service)
|
||||||
|
elif self._has_lbaas_spec_changes(service, loadbalancer_crd):
|
||||||
|
loadbalancer_crd = self._update_crd_spec(loadbalancer_crd, service)
|
||||||
|
|
||||||
def _is_supported_type(self, service):
|
def _is_supported_type(self, service):
|
||||||
spec = service['spec']
|
spec = service['spec']
|
||||||
|
@ -75,12 +77,22 @@ class LBaaSSpecHandler(k8s_base.ResourceEventHandler):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _should_ignore(self, service):
|
def _should_ignore(self, service):
|
||||||
return (not(self._has_selector(service)) or
|
return (not(self._has_clusterip(service)) or
|
||||||
not(self._has_clusterip(service)) or
|
|
||||||
not(self._is_supported_type(service)))
|
not(self._is_supported_type(service)))
|
||||||
|
|
||||||
def _has_selector(self, service):
|
def _patch_service_finalizer(self, service):
|
||||||
return service['spec'].get('selector')
|
k8s = clients.get_kubernetes_client()
|
||||||
|
k8s.add_finalizer(service, k_const.SERVICE_FINALIZER)
|
||||||
|
|
||||||
|
def on_finalize(self, service):
|
||||||
|
k8s = clients.get_kubernetes_client()
|
||||||
|
|
||||||
|
svc_name = service['metadata']['name']
|
||||||
|
svc_namespace = service['metadata']['namespace']
|
||||||
|
|
||||||
|
klb_crd_path = (f"{k_const.K8S_API_CRD_NAMESPACES}/"
|
||||||
|
f"{svc_namespace}/kuryrloadbalancers/{svc_name}")
|
||||||
|
k8s.delete(klb_crd_path)
|
||||||
|
|
||||||
def _has_clusterip(self, service):
|
def _has_clusterip(self, service):
|
||||||
# ignore headless service, clusterIP is None
|
# ignore headless service, clusterIP is None
|
||||||
|
@ -97,45 +109,113 @@ class LBaaSSpecHandler(k8s_base.ResourceEventHandler):
|
||||||
if len(subnet_ids) != 1:
|
if len(subnet_ids) != 1:
|
||||||
raise k_exc.IntegrityError(_(
|
raise k_exc.IntegrityError(_(
|
||||||
"Found %(num)s subnets for service %(link)s IP %(ip)s") % {
|
"Found %(num)s subnets for service %(link)s IP %(ip)s") % {
|
||||||
'link': service['metadata']['selfLink'],
|
'link': service['metadata']['selfLink'],
|
||||||
'ip': ip,
|
'ip': ip,
|
||||||
'num': len(subnet_ids)})
|
'num': len(subnet_ids)})
|
||||||
|
|
||||||
return subnet_ids.pop()
|
return subnet_ids.pop()
|
||||||
|
|
||||||
def _generate_lbaas_spec(self, service):
|
def create_crd_spec(self, service):
|
||||||
project_id = self._drv_project.get_project(service)
|
svc_name = service['metadata']['name']
|
||||||
ip = self._get_service_ip(service)
|
svc_namespace = service['metadata']['namespace']
|
||||||
subnet_id = self._get_subnet_id(service, project_id, ip)
|
kubernetes = clients.get_kubernetes_client()
|
||||||
ports = self._generate_lbaas_port_specs(service)
|
svc_ip = self._get_service_ip(service)
|
||||||
sg_ids = self._drv_sg.get_security_groups(service, project_id)
|
|
||||||
spec_type = service['spec'].get('type')
|
|
||||||
spec_lb_ip = service['spec'].get('loadBalancerIP')
|
spec_lb_ip = service['spec'].get('loadBalancerIP')
|
||||||
|
ports = service['spec'].get('ports')
|
||||||
|
for port in ports:
|
||||||
|
if type(port['targetPort']) == int:
|
||||||
|
port['targetPort'] = str(port['targetPort'])
|
||||||
|
project_id = self._drv_project.get_project(service)
|
||||||
|
sg_ids = self._drv_sg.get_security_groups(service, project_id)
|
||||||
|
subnet_id = self._get_subnet_id(service, project_id, svc_ip)
|
||||||
|
spec_type = service['spec'].get('type')
|
||||||
|
loadbalancer_crd = {
|
||||||
|
'apiVersion': 'openstack.org/v1',
|
||||||
|
'kind': 'KuryrLoadBalancer',
|
||||||
|
'metadata': {
|
||||||
|
'name': svc_name,
|
||||||
|
'finalizers': [k_const.KURYRLB_FINALIZER],
|
||||||
|
},
|
||||||
|
'spec': {
|
||||||
|
'ip': svc_ip,
|
||||||
|
'ports': ports,
|
||||||
|
'project_id': project_id,
|
||||||
|
'security_groups_ids': sg_ids,
|
||||||
|
'subnet_id': subnet_id,
|
||||||
|
'type': spec_type
|
||||||
|
},
|
||||||
|
'status': {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return obj_lbaas.LBaaSServiceSpec(ip=ip,
|
if spec_lb_ip is not None:
|
||||||
project_id=project_id,
|
loadbalancer_crd['spec']['lb_ip'] = spec_lb_ip
|
||||||
subnet_id=subnet_id,
|
|
||||||
ports=ports,
|
|
||||||
security_groups_ids=sg_ids,
|
|
||||||
type=spec_type,
|
|
||||||
lb_ip=spec_lb_ip)
|
|
||||||
|
|
||||||
def _has_lbaas_spec_changes(self, service, lbaas_spec):
|
try:
|
||||||
return (self._has_ip_changes(service, lbaas_spec) or
|
kubernetes.post('{}/{}/kuryrloadbalancers'.format(
|
||||||
utils.has_port_changes(service, lbaas_spec))
|
k_const.K8S_API_CRD_NAMESPACES, svc_namespace),
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sConflict:
|
||||||
|
raise k_exc.ResourceNotReady(svc_name)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception("Kubernetes Client Exception creating "
|
||||||
|
"kuryrloadbalancer CRD. %s"
|
||||||
|
% k_exc.K8sClientException)
|
||||||
|
raise
|
||||||
|
return loadbalancer_crd
|
||||||
|
|
||||||
def _has_ip_changes(self, service, lbaas_spec):
|
def _update_crd_spec(self, loadbalancer_crd, service):
|
||||||
|
svc_ip = self._get_service_ip(service)
|
||||||
|
ports = service['spec'].get('ports')
|
||||||
|
for port in ports:
|
||||||
|
if type(port['targetPort']) == int:
|
||||||
|
port['targetPort'] = str(port['targetPort'])
|
||||||
|
project_id = self._drv_project.get_project(service)
|
||||||
|
sg_ids = self._drv_sg.get_security_groups(service, project_id)
|
||||||
|
subnet_id = self._get_subnet_id(service, project_id, svc_ip)
|
||||||
|
spec_type = service['spec'].get('type')
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
|
||||||
|
patch = {
|
||||||
|
'spec': {
|
||||||
|
'ip': svc_ip,
|
||||||
|
'ports': ports,
|
||||||
|
'project_id': project_id,
|
||||||
|
'security_groups_ids': sg_ids,
|
||||||
|
'subnet_id': subnet_id,
|
||||||
|
'type': spec_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.debug('Patching KuryrLoadBalancer CRD %s', loadbalancer_crd)
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('spec', loadbalancer_crd['metadata'][
|
||||||
|
'selfLink'], patch['spec'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadBalancer CRD not found %s', loadbalancer_crd)
|
||||||
|
except k_exc.K8sConflict:
|
||||||
|
raise k_exc.ResourceNotReady(loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating kuryrnet CRD %s', loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
return loadbalancer_crd
|
||||||
|
|
||||||
|
def _has_lbaas_spec_changes(self, service, loadbalancer_crd):
|
||||||
|
return (self._has_ip_changes(service, loadbalancer_crd) or
|
||||||
|
utils.has_port_changes(service, loadbalancer_crd))
|
||||||
|
|
||||||
|
def _has_ip_changes(self, service, loadbalancer_crd):
|
||||||
link = service['metadata']['selfLink']
|
link = service['metadata']['selfLink']
|
||||||
svc_ip = self._get_service_ip(service)
|
svc_ip = self._get_service_ip(service)
|
||||||
|
|
||||||
if not lbaas_spec:
|
if loadbalancer_crd['spec'].get('ip') is None:
|
||||||
if svc_ip:
|
if svc_ip is None:
|
||||||
LOG.debug("LBaaS spec is missing for %(link)s"
|
return False
|
||||||
% {'link': link})
|
return True
|
||||||
return True
|
|
||||||
elif str(lbaas_spec.ip) != svc_ip:
|
elif str(loadbalancer_crd['spec'].get('ip')) != svc_ip:
|
||||||
LOG.debug("LBaaS spec IP %(spec_ip)s != %(svc_ip)s for %(link)s"
|
LOG.debug("LBaaS spec IP %(spec_ip)s != %(svc_ip)s for %(link)s"
|
||||||
% {'spec_ip': lbaas_spec.ip,
|
% {'spec_ip': loadbalancer_crd['spec']['ip'],
|
||||||
'svc_ip': svc_ip,
|
'svc_ip': svc_ip,
|
||||||
'link': link})
|
'link': link})
|
||||||
return True
|
return True
|
||||||
|
@ -147,10 +227,10 @@ class LBaaSSpecHandler(k8s_base.ResourceEventHandler):
|
||||||
for port in utils.get_service_ports(service)]
|
for port in utils.get_service_ports(service)]
|
||||||
|
|
||||||
|
|
||||||
class LoadBalancerHandler(k8s_base.ResourceEventHandler):
|
class EndpointsHandler(k8s_base.ResourceEventHandler):
|
||||||
"""LoadBalancerHandler handles K8s Endpoints events.
|
"""EndpointsHandler handles K8s Endpoints events.
|
||||||
|
|
||||||
LoadBalancerHandler handles K8s Endpoints events and tracks changes in
|
EndpointsHandler handles K8s Endpoints events and tracks changes in
|
||||||
LBaaSServiceSpec to update Neutron LBaaS accordingly and to reflect its'
|
LBaaSServiceSpec to update Neutron LBaaS accordingly and to reflect its'
|
||||||
actual state in LBaaSState.
|
actual state in LBaaSState.
|
||||||
"""
|
"""
|
||||||
|
@ -159,13 +239,11 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
|
||||||
OBJECT_WATCH_PATH = "%s/%s" % (k_const.K8S_API_BASE, "endpoints")
|
OBJECT_WATCH_PATH = "%s/%s" % (k_const.K8S_API_BASE, "endpoints")
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(LoadBalancerHandler, self).__init__()
|
super(EndpointsHandler, self).__init__()
|
||||||
self._drv_lbaas = drv_base.LBaaSDriver.get_instance()
|
self._drv_lbaas = drv_base.LBaaSDriver.get_instance()
|
||||||
self._drv_pod_project = drv_base.PodProjectDriver.get_instance()
|
self._drv_pod_project = drv_base.PodProjectDriver.get_instance()
|
||||||
self._drv_pod_subnets = drv_base.PodSubnetsDriver.get_instance()
|
self._drv_pod_subnets = drv_base.PodSubnetsDriver.get_instance()
|
||||||
self._drv_service_pub_ip = drv_base.ServicePubIpDriver.get_instance()
|
self._drv_service_pub_ip = drv_base.ServicePubIpDriver.get_instance()
|
||||||
self._drv_project = drv_base.ServiceProjectDriver.get_instance()
|
|
||||||
self._drv_sg = drv_base.ServiceSecurityGroupsDriver.get_instance()
|
|
||||||
# Note(yboaron) LBaaS driver supports 'provider' parameter in
|
# Note(yboaron) LBaaS driver supports 'provider' parameter in
|
||||||
# Load Balancer creation flow.
|
# Load Balancer creation flow.
|
||||||
# We need to set the requested load balancer provider
|
# We need to set the requested load balancer provider
|
||||||
|
@ -175,104 +253,40 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
|
||||||
!= 'default'):
|
!= 'default'):
|
||||||
self._lb_provider = (
|
self._lb_provider = (
|
||||||
config.CONF.kubernetes.endpoints_driver_octavia_provider)
|
config.CONF.kubernetes.endpoints_driver_octavia_provider)
|
||||||
eventlet.spawn(self._cleanup_leftover_lbaas)
|
|
||||||
|
|
||||||
def on_present(self, endpoints):
|
def on_present(self, endpoints):
|
||||||
lbaas_spec = utils.get_lbaas_spec(endpoints)
|
k8s = clients.get_kubernetes_client()
|
||||||
if self._should_ignore(endpoints, lbaas_spec):
|
loadbalancer_crd = k8s.get_loadbalancer_crd(endpoints)
|
||||||
|
|
||||||
|
if not self._has_pods(endpoints):
|
||||||
LOG.debug("Ignoring Kubernetes endpoints %s",
|
LOG.debug("Ignoring Kubernetes endpoints %s",
|
||||||
endpoints['metadata']['name'])
|
endpoints['metadata']['name'])
|
||||||
return
|
return
|
||||||
|
|
||||||
lbaas_state = utils.get_lbaas_state(endpoints)
|
if loadbalancer_crd is None:
|
||||||
if not lbaas_state:
|
loadbalancer_crd = self._create_crd_spec(endpoints)
|
||||||
lbaas_state = obj_lbaas.LBaaSState()
|
else:
|
||||||
elif (lbaas_state.loadbalancer and self._lb_provider and
|
loadbalancer_crd = self._update_crd_spec(loadbalancer_crd,
|
||||||
self._lb_provider != lbaas_state.loadbalancer.provider):
|
endpoints)
|
||||||
LOG.info("LoadBalancer associated to the service does not match "
|
|
||||||
"the current provider: %s", lbaas_state.loadbalancer.id)
|
|
||||||
lb_client = clients.get_loadbalancer_client()
|
|
||||||
try:
|
|
||||||
lb_client.get_load_balancer(lbaas_state.loadbalancer.id)
|
|
||||||
except os_exc.NotFoundException:
|
|
||||||
# NOTE(ltomasbo): If the loadbalancer is gone, remove the
|
|
||||||
# annotations to ensure it is reprocessed
|
|
||||||
lbaas_state.loadbalancer = None
|
|
||||||
lbaas_state.pools = []
|
|
||||||
lbaas_state.listeners = []
|
|
||||||
lbaas_state.members = []
|
|
||||||
utils.set_lbaas_state(endpoints, lbaas_state)
|
|
||||||
return
|
|
||||||
|
|
||||||
if self._sync_lbaas_members(endpoints, lbaas_state, lbaas_spec):
|
def _has_lbaas_spec_changes(self, endpoints, loadbalancer_crd):
|
||||||
# Note(yboaron) For LoadBalancer services, we should allocate FIP,
|
return (self._has_ip_changes(endpoints, loadbalancer_crd) or
|
||||||
# associate it to LB VIP and update K8S service status
|
utils.has_port_changes(endpoints, loadbalancer_crd))
|
||||||
if lbaas_state.service_pub_ip_info is None:
|
|
||||||
service_pub_ip_info = (
|
|
||||||
self._drv_service_pub_ip.acquire_service_pub_ip_info(
|
|
||||||
lbaas_spec.type,
|
|
||||||
lbaas_spec.lb_ip,
|
|
||||||
lbaas_spec.project_id,
|
|
||||||
lbaas_state.loadbalancer.port_id))
|
|
||||||
if service_pub_ip_info:
|
|
||||||
self._drv_service_pub_ip.associate_pub_ip(
|
|
||||||
service_pub_ip_info, lbaas_state.loadbalancer.port_id)
|
|
||||||
lbaas_state.service_pub_ip_info = service_pub_ip_info
|
|
||||||
self._update_lb_status(
|
|
||||||
endpoints,
|
|
||||||
lbaas_state.service_pub_ip_info.ip_addr)
|
|
||||||
# REVISIT(ivc): since _sync_lbaas_members is responsible for
|
|
||||||
# creating all lbaas components (i.e. load balancer, listeners,
|
|
||||||
# pools, members), it is currently possible for it to fail (due
|
|
||||||
# to invalid Kuryr/K8s/Neutron configuration, e.g. Members' IPs
|
|
||||||
# not belonging to configured Neutron subnet or Service IP being
|
|
||||||
# in use by gateway or VMs) leaving some Neutron entities without
|
|
||||||
# properly updating annotation. Some sort of failsafe mechanism is
|
|
||||||
# required to deal with such situations (e.g. cleanup, or skip
|
|
||||||
# failing items, or validate configuration) to prevent annotation
|
|
||||||
# being out of sync with the actual Neutron state.
|
|
||||||
try:
|
|
||||||
utils.set_lbaas_state(endpoints, lbaas_state)
|
|
||||||
except k_exc.K8sResourceNotFound:
|
|
||||||
# Note(yboaron) It's impossible to store neutron resources
|
|
||||||
# in K8S object since object was deleted. In that case
|
|
||||||
# we should rollback all neutron resources.
|
|
||||||
LOG.debug("LoadBalancerHandler failed to store Openstack "
|
|
||||||
"resources in K8S object (not found)")
|
|
||||||
self.on_deleted(endpoints, lbaas_state)
|
|
||||||
|
|
||||||
def on_deleted(self, endpoints, lbaas_state=None):
|
def _has_ip_changes(self, endpoints, loadbalancer_crd):
|
||||||
if lbaas_state is None:
|
link = endpoints['metadata']['selfLink']
|
||||||
lbaas_state = utils.get_lbaas_state(endpoints)
|
endpoint_ip = endpoints['subsets']['addresses'].get('ip')
|
||||||
if not lbaas_state:
|
endpoint_crd_ip = loadbalancer_crd['spec'].get('ip')
|
||||||
return
|
|
||||||
# NOTE(ivc): deleting pool deletes its members
|
|
||||||
self._drv_lbaas.release_loadbalancer(
|
|
||||||
loadbalancer=lbaas_state.loadbalancer)
|
|
||||||
if lbaas_state.service_pub_ip_info:
|
|
||||||
self._drv_service_pub_ip.release_pub_ip(
|
|
||||||
lbaas_state.service_pub_ip_info)
|
|
||||||
|
|
||||||
def _should_ignore(self, endpoints, lbaas_spec):
|
if endpoint_crd_ip != endpoint_ip:
|
||||||
# NOTE(ltomasbo): we must wait until service handler has annotated the
|
LOG.debug("LBaaS spec IP %(endpoint_crd_ip)s !="
|
||||||
# endpoints to process them. Thus, if annotations are not updated to
|
" %(endpoint_ip)s for %(link)s"
|
||||||
# match the endpoints information, we should skip the event
|
% {'endpoint_crd_ip': endpoint_crd_ip,
|
||||||
return not(lbaas_spec and
|
'endpoint_ip': endpoint_ip,
|
||||||
self._has_pods(endpoints) and
|
'link': link})
|
||||||
self._svc_handler_annotations_updated(endpoints,
|
return True
|
||||||
lbaas_spec))
|
|
||||||
|
|
||||||
def _svc_handler_annotations_updated(self, endpoints, lbaas_spec):
|
return False
|
||||||
svc_link = self._get_service_link(endpoints)
|
|
||||||
k8s = clients.get_kubernetes_client()
|
|
||||||
service = k8s.get(svc_link)
|
|
||||||
if utils.has_port_changes(service, lbaas_spec):
|
|
||||||
# NOTE(ltomasbo): Ensuring lbaas_spec annotated on the endpoints
|
|
||||||
# is in sync with the service status, i.e., upon a service
|
|
||||||
# modification it will ensure endpoint modifications are not
|
|
||||||
# handled until the service handler has performed its annotations
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _has_pods(self, endpoints):
|
def _has_pods(self, endpoints):
|
||||||
ep_subsets = endpoints.get('subsets', [])
|
ep_subsets = endpoints.get('subsets', [])
|
||||||
|
@ -283,327 +297,58 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
|
||||||
for address in subset.get('addresses', [])
|
for address in subset.get('addresses', [])
|
||||||
if address.get('targetRef', {}).get('kind') == 'Pod')
|
if address.get('targetRef', {}).get('kind') == 'Pod')
|
||||||
|
|
||||||
def _sync_lbaas_members(self, endpoints, lbaas_state, lbaas_spec):
|
def _create_crd_spec(self, endpoints):
|
||||||
changed = False
|
endpoints_name = endpoints['metadata']['name']
|
||||||
|
namespace = endpoints['metadata']['namespace']
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
|
||||||
if (self._has_pods(endpoints) and
|
subsets = endpoints.get('subsets', [])
|
||||||
self._remove_unused_members(endpoints, lbaas_state,
|
|
||||||
lbaas_spec)):
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
if self._sync_lbaas_pools(endpoints, lbaas_state, lbaas_spec):
|
loadbalancer_crd = {
|
||||||
changed = True
|
'apiVersion': 'openstack.org/v1',
|
||||||
|
'kind': 'KuryrLoadBalancer',
|
||||||
|
'metadata': {
|
||||||
|
'name': endpoints_name,
|
||||||
|
'finalizers': [k_const.KURYRLB_FINALIZER]
|
||||||
|
},
|
||||||
|
'spec': {
|
||||||
|
'subsets': subsets
|
||||||
|
},
|
||||||
|
'status': {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (self._has_pods(endpoints) and
|
|
||||||
self._add_new_members(endpoints, lbaas_state, lbaas_spec)):
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
return changed
|
|
||||||
|
|
||||||
def _sync_lbaas_sgs(self, endpoints, lbaas_state):
|
|
||||||
svc_link = self._get_service_link(endpoints)
|
|
||||||
k8s = clients.get_kubernetes_client()
|
|
||||||
service = k8s.get(svc_link)
|
|
||||||
|
|
||||||
lb = lbaas_state.loadbalancer
|
|
||||||
# NOTE(maysams) It's possible that while the service annotation
|
|
||||||
# is added the backend pods on that service are not yet created
|
|
||||||
# resulting in no security groups retrieved for the service.
|
|
||||||
# Let's retrieve again to ensure is updated.
|
|
||||||
project_id = self._drv_project.get_project(service)
|
|
||||||
lb_sgs = self._drv_sg.get_security_groups(service, project_id)
|
|
||||||
lb.security_groups = lb_sgs
|
|
||||||
|
|
||||||
def _add_new_members(self, endpoints, lbaas_state, lbaas_spec):
|
|
||||||
changed = False
|
|
||||||
|
|
||||||
if config.CONF.octavia_defaults.enforce_sg_rules:
|
|
||||||
try:
|
|
||||||
self._sync_lbaas_sgs(endpoints, lbaas_state)
|
|
||||||
except k_exc.K8sResourceNotFound:
|
|
||||||
LOG.debug("The svc has been deleted while processing"
|
|
||||||
" the endpoints update. No need to add new"
|
|
||||||
" members.")
|
|
||||||
|
|
||||||
lsnr_by_id = {listener.id: listener
|
|
||||||
for listener in lbaas_state.listeners}
|
|
||||||
pool_by_lsnr_port = {(lsnr_by_id[p.listener_id].protocol,
|
|
||||||
lsnr_by_id[p.listener_id].port): p
|
|
||||||
for p in lbaas_state.pools}
|
|
||||||
|
|
||||||
# NOTE(yboaron): Since LBaaSv2 doesn't support UDP load balancing,
|
|
||||||
# the LBaaS driver will return 'None' in case of UDP port
|
|
||||||
# listener creation.
|
|
||||||
# we should consider the case in which
|
|
||||||
# 'pool_by_lsnr_port[p.protocol, p.port]' is missing
|
|
||||||
pool_by_tgt_name = {}
|
|
||||||
for p in lbaas_spec.ports:
|
|
||||||
try:
|
|
||||||
pool_by_tgt_name[p.name] = pool_by_lsnr_port[p.protocol,
|
|
||||||
p.port]
|
|
||||||
except KeyError:
|
|
||||||
continue
|
|
||||||
current_targets = {(str(m.ip), m.port, m.pool_id)
|
|
||||||
for m in lbaas_state.members}
|
|
||||||
|
|
||||||
for subset in endpoints.get('subsets', []):
|
|
||||||
subset_ports = subset.get('ports', [])
|
|
||||||
for subset_address in subset.get('addresses', []):
|
|
||||||
try:
|
|
||||||
target_ip = subset_address['ip']
|
|
||||||
target_ref = subset_address['targetRef']
|
|
||||||
if target_ref['kind'] != k_const.K8S_OBJ_POD:
|
|
||||||
continue
|
|
||||||
except KeyError:
|
|
||||||
continue
|
|
||||||
if not pool_by_tgt_name:
|
|
||||||
continue
|
|
||||||
for subset_port in subset_ports:
|
|
||||||
target_port = subset_port['port']
|
|
||||||
port_name = subset_port.get('name')
|
|
||||||
try:
|
|
||||||
pool = pool_by_tgt_name[port_name]
|
|
||||||
except KeyError:
|
|
||||||
LOG.debug("No pool found for port: %r", port_name)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if (target_ip, target_port, pool.id) in current_targets:
|
|
||||||
continue
|
|
||||||
# TODO(apuimedo): Do not pass subnet_id at all when in
|
|
||||||
# L3 mode once old neutron-lbaasv2 is not supported, as
|
|
||||||
# octavia does not require it
|
|
||||||
if (config.CONF.octavia_defaults.member_mode ==
|
|
||||||
k_const.OCTAVIA_L2_MEMBER_MODE):
|
|
||||||
try:
|
|
||||||
member_subnet_id = self._get_pod_subnet(target_ref,
|
|
||||||
target_ip)
|
|
||||||
except k_exc.K8sResourceNotFound:
|
|
||||||
LOG.debug("Member namespace has been deleted. No "
|
|
||||||
"need to add the members as it is "
|
|
||||||
"going to be deleted")
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
# We use the service subnet id so that the connectivity
|
|
||||||
# from VIP to pods happens in layer 3 mode, i.e.,
|
|
||||||
# routed.
|
|
||||||
member_subnet_id = lbaas_state.loadbalancer.subnet_id
|
|
||||||
first_member_of_the_pool = True
|
|
||||||
for member in lbaas_state.members:
|
|
||||||
if pool.id == member.pool_id:
|
|
||||||
first_member_of_the_pool = False
|
|
||||||
break
|
|
||||||
if first_member_of_the_pool:
|
|
||||||
listener_port = lsnr_by_id[pool.listener_id].port
|
|
||||||
else:
|
|
||||||
listener_port = None
|
|
||||||
|
|
||||||
member = self._drv_lbaas.ensure_member(
|
|
||||||
loadbalancer=lbaas_state.loadbalancer,
|
|
||||||
pool=pool,
|
|
||||||
subnet_id=member_subnet_id,
|
|
||||||
ip=target_ip,
|
|
||||||
port=target_port,
|
|
||||||
target_ref_namespace=target_ref['namespace'],
|
|
||||||
target_ref_name=target_ref['name'],
|
|
||||||
listener_port=listener_port)
|
|
||||||
lbaas_state.members.append(member)
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
return changed
|
|
||||||
|
|
||||||
def _get_pod_subnet(self, target_ref, ip):
|
|
||||||
# REVISIT(ivc): consider using true pod object instead
|
|
||||||
pod = {'kind': target_ref['kind'],
|
|
||||||
'metadata': {'name': target_ref['name'],
|
|
||||||
'namespace': target_ref['namespace']}}
|
|
||||||
project_id = self._drv_pod_project.get_project(pod)
|
|
||||||
subnets_map = self._drv_pod_subnets.get_subnets(pod, project_id)
|
|
||||||
subnet_ids = [subnet_id for subnet_id, network in subnets_map.items()
|
|
||||||
for subnet in network.subnets.objects
|
|
||||||
if ip in subnet.cidr]
|
|
||||||
if subnet_ids:
|
|
||||||
return subnet_ids[0]
|
|
||||||
else:
|
|
||||||
# NOTE(ltomasbo): We are assuming that if ip is not on the
|
|
||||||
# pod subnet is because the member is using hostnetworking. In
|
|
||||||
# this worker_nodes_subnet will be used
|
|
||||||
return config.CONF.pod_vif_nested.worker_nodes_subnet
|
|
||||||
|
|
||||||
def _get_port_in_pool(self, pool, lbaas_state, lbaas_spec):
|
|
||||||
for listener in lbaas_state.listeners:
|
|
||||||
if listener.id != pool.listener_id:
|
|
||||||
continue
|
|
||||||
for port in lbaas_spec.ports:
|
|
||||||
if (listener.port == port.port and
|
|
||||||
listener.protocol == port.protocol):
|
|
||||||
return port
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _remove_unused_members(self, endpoints, lbaas_state, lbaas_spec):
|
|
||||||
spec_ports = {}
|
|
||||||
for pool in lbaas_state.pools:
|
|
||||||
port = self._get_port_in_pool(pool, lbaas_state, lbaas_spec)
|
|
||||||
if port:
|
|
||||||
spec_ports[port.name] = pool.id
|
|
||||||
|
|
||||||
current_targets = {(a['ip'], a.get('targetRef', {}).get('name', ''),
|
|
||||||
p['port'], spec_ports.get(p.get('name')))
|
|
||||||
for s in endpoints['subsets']
|
|
||||||
for a in s['addresses']
|
|
||||||
for p in s['ports']
|
|
||||||
if p.get('name') in spec_ports}
|
|
||||||
|
|
||||||
removed_ids = set()
|
|
||||||
for member in lbaas_state.members:
|
|
||||||
try:
|
|
||||||
member_name = member.name
|
|
||||||
# NOTE: The member name is compose of:
|
|
||||||
# NAMESPACE_NAME/POD_NAME:PROTOCOL_PORT
|
|
||||||
pod_name = member_name.split('/')[1].split(':')[0]
|
|
||||||
except AttributeError:
|
|
||||||
pod_name = ""
|
|
||||||
if ((str(member.ip), pod_name, member.port, member.pool_id) in
|
|
||||||
current_targets):
|
|
||||||
continue
|
|
||||||
self._drv_lbaas.release_member(lbaas_state.loadbalancer,
|
|
||||||
member)
|
|
||||||
removed_ids.add(member.id)
|
|
||||||
|
|
||||||
if removed_ids:
|
|
||||||
lbaas_state.members = [m for m in lbaas_state.members
|
|
||||||
if m.id not in removed_ids]
|
|
||||||
return bool(removed_ids)
|
|
||||||
|
|
||||||
def _sync_lbaas_pools(self, endpoints, lbaas_state, lbaas_spec):
|
|
||||||
changed = False
|
|
||||||
|
|
||||||
if self._remove_unused_pools(lbaas_state, lbaas_spec):
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
if self._sync_lbaas_listeners(endpoints, lbaas_state, lbaas_spec):
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
if self._add_new_pools(lbaas_state, lbaas_spec):
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
return changed
|
|
||||||
|
|
||||||
def _add_new_pools(self, lbaas_state, lbaas_spec):
|
|
||||||
changed = False
|
|
||||||
|
|
||||||
current_listeners_ids = {pool.listener_id
|
|
||||||
for pool in lbaas_state.pools}
|
|
||||||
for listener in lbaas_state.listeners:
|
|
||||||
if listener.id in current_listeners_ids:
|
|
||||||
continue
|
|
||||||
pool = self._drv_lbaas.ensure_pool(lbaas_state.loadbalancer,
|
|
||||||
listener)
|
|
||||||
lbaas_state.pools.append(pool)
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
return changed
|
|
||||||
|
|
||||||
def _is_pool_in_spec(self, pool, lbaas_state, lbaas_spec):
|
|
||||||
# NOTE(yboaron): in order to check if a specific pool is in lbaas_spec
|
|
||||||
# we should:
|
|
||||||
# 1. get the listener that pool is attached to
|
|
||||||
# 2. check if listener's attributes appear in lbaas_spec.
|
|
||||||
for listener in lbaas_state.listeners:
|
|
||||||
if listener.id != pool.listener_id:
|
|
||||||
continue
|
|
||||||
for port in lbaas_spec.ports:
|
|
||||||
if (listener.port == port.port and
|
|
||||||
listener.protocol == port.protocol):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _remove_unused_pools(self, lbaas_state, lbaas_spec):
|
|
||||||
removed_ids = set()
|
|
||||||
for pool in lbaas_state.pools:
|
|
||||||
if self._is_pool_in_spec(pool, lbaas_state, lbaas_spec):
|
|
||||||
continue
|
|
||||||
self._drv_lbaas.release_pool(lbaas_state.loadbalancer,
|
|
||||||
pool)
|
|
||||||
removed_ids.add(pool.id)
|
|
||||||
if removed_ids:
|
|
||||||
lbaas_state.pools = [p for p in lbaas_state.pools
|
|
||||||
if p.id not in removed_ids]
|
|
||||||
lbaas_state.members = [m for m in lbaas_state.members
|
|
||||||
if m.pool_id not in removed_ids]
|
|
||||||
return bool(removed_ids)
|
|
||||||
|
|
||||||
def _sync_lbaas_listeners(self, endpoints, lbaas_state, lbaas_spec):
|
|
||||||
changed = False
|
|
||||||
|
|
||||||
if self._remove_unused_listeners(endpoints, lbaas_state, lbaas_spec):
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
if self._sync_lbaas_loadbalancer(endpoints, lbaas_state, lbaas_spec):
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
if self._add_new_listeners(endpoints, lbaas_spec, lbaas_state):
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
return changed
|
|
||||||
|
|
||||||
def _add_new_listeners(self, endpoints, lbaas_spec, lbaas_state):
|
|
||||||
changed = False
|
|
||||||
lbaas_spec_ports = sorted(lbaas_spec.ports, key=lambda x: x.protocol)
|
|
||||||
for port_spec in lbaas_spec_ports:
|
|
||||||
protocol = port_spec.protocol
|
|
||||||
port = port_spec.port
|
|
||||||
name = "%s:%s" % (lbaas_state.loadbalancer.name, protocol)
|
|
||||||
listener = [listener for listener in lbaas_state.listeners
|
|
||||||
if listener.port == port and
|
|
||||||
listener.protocol == protocol]
|
|
||||||
if listener:
|
|
||||||
continue
|
|
||||||
# FIXME (maysams): Due to a bug in Octavia, which does
|
|
||||||
# not allows listeners with same port but different
|
|
||||||
# protocols to co-exist, we need to skip the creation of
|
|
||||||
# listeners that have the same port as an existing one.
|
|
||||||
listener = [listener for listener in lbaas_state.listeners if
|
|
||||||
listener.port == port]
|
|
||||||
if listener and not self._drv_lbaas.double_listeners_supported():
|
|
||||||
LOG.warning("Skipping listener creation for %s as another one"
|
|
||||||
" already exists with port %s", name, port)
|
|
||||||
continue
|
|
||||||
listener = self._drv_lbaas.ensure_listener(
|
|
||||||
loadbalancer=lbaas_state.loadbalancer,
|
|
||||||
protocol=protocol,
|
|
||||||
port=port,
|
|
||||||
service_type=lbaas_spec.type)
|
|
||||||
if listener is not None:
|
|
||||||
lbaas_state.listeners.append(listener)
|
|
||||||
changed = True
|
|
||||||
return changed
|
|
||||||
|
|
||||||
def _remove_unused_listeners(self, endpoints, lbaas_state, lbaas_spec):
|
|
||||||
current_listeners = {p.listener_id for p in lbaas_state.pools}
|
|
||||||
|
|
||||||
removed_ids = set()
|
|
||||||
for listener in lbaas_state.listeners:
|
|
||||||
if listener.id in current_listeners:
|
|
||||||
continue
|
|
||||||
self._drv_lbaas.release_listener(lbaas_state.loadbalancer,
|
|
||||||
listener)
|
|
||||||
removed_ids.add(listener.id)
|
|
||||||
if removed_ids:
|
|
||||||
lbaas_state.listeners = [
|
|
||||||
listener for listener in lbaas_state.listeners
|
|
||||||
if listener.id not in removed_ids]
|
|
||||||
return bool(removed_ids)
|
|
||||||
|
|
||||||
def _update_lb_status(self, endpoints, lb_ip_address):
|
|
||||||
status_data = {"loadBalancer": {
|
|
||||||
"ingress": [{"ip": lb_ip_address.format()}]}}
|
|
||||||
k8s = clients.get_kubernetes_client()
|
|
||||||
svc_status_link = self._get_service_link(endpoints) + '/status'
|
|
||||||
try:
|
try:
|
||||||
k8s.patch("status", svc_status_link, status_data)
|
kubernetes.post('{}/{}/kuryrloadbalancers'.format(
|
||||||
|
k_const.K8S_API_CRD_NAMESPACES, namespace), loadbalancer_crd)
|
||||||
|
except k_exc.K8sConflict:
|
||||||
|
raise k_exc.ResourceNotReady(loadbalancer_crd)
|
||||||
except k_exc.K8sClientException:
|
except k_exc.K8sClientException:
|
||||||
# REVISIT(ivc): only raise ResourceNotReady for NotFound
|
LOG.exception("Kubernetes Client Exception creating "
|
||||||
raise k_exc.ResourceNotReady(svc_status_link)
|
"kuryrloadbalancer CRD. %s" %
|
||||||
|
k_exc.K8sClientException)
|
||||||
|
raise
|
||||||
|
return loadbalancer_crd
|
||||||
|
|
||||||
|
def _update_crd_spec(self, loadbalancer_crd, endpoints):
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
subsets = endpoints.get('subsets')
|
||||||
|
lbaas_update_crd = {
|
||||||
|
'subsets': subsets
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('spec', loadbalancer_crd['metadata'][
|
||||||
|
'selfLink'], lbaas_update_crd)
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s', loadbalancer_crd)
|
||||||
|
except k_exc.K8sConflict:
|
||||||
|
raise k_exc.ResourceNotReady(loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryrLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
|
||||||
|
return loadbalancer_crd
|
||||||
|
|
||||||
def _get_service_link(self, endpoints):
|
def _get_service_link(self, endpoints):
|
||||||
ep_link = endpoints['metadata']['selfLink']
|
ep_link = endpoints['metadata']['selfLink']
|
||||||
|
@ -612,129 +357,6 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
|
||||||
if link_parts[-2] != 'endpoints':
|
if link_parts[-2] != 'endpoints':
|
||||||
raise k_exc.IntegrityError(_(
|
raise k_exc.IntegrityError(_(
|
||||||
"Unsupported endpoints link: %(link)s") % {
|
"Unsupported endpoints link: %(link)s") % {
|
||||||
'link': ep_link})
|
'link': ep_link})
|
||||||
link_parts[-2] = 'services'
|
link_parts[-2] = 'services'
|
||||||
return "/".join(link_parts)
|
return "/".join(link_parts)
|
||||||
|
|
||||||
def _sync_lbaas_loadbalancer(self, endpoints, lbaas_state, lbaas_spec):
|
|
||||||
changed = False
|
|
||||||
lb = lbaas_state.loadbalancer
|
|
||||||
|
|
||||||
if lb and lb.ip != lbaas_spec.ip:
|
|
||||||
# if loadbalancerIP was associated to lbaas VIP, disassociate it.
|
|
||||||
if lbaas_state.service_pub_ip_info:
|
|
||||||
self._drv_service_pub_ip.disassociate_pub_ip(
|
|
||||||
lbaas_state.service_pub_ip_info)
|
|
||||||
|
|
||||||
self._drv_lbaas.release_loadbalancer(
|
|
||||||
loadbalancer=lb)
|
|
||||||
lb = None
|
|
||||||
lbaas_state.pools = []
|
|
||||||
lbaas_state.listeners = []
|
|
||||||
lbaas_state.members = []
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
if not lb:
|
|
||||||
if lbaas_spec.ip:
|
|
||||||
lb_name = self._drv_lbaas.get_service_loadbalancer_name(
|
|
||||||
endpoints['metadata']['namespace'],
|
|
||||||
endpoints['metadata']['name'])
|
|
||||||
lb = self._drv_lbaas.ensure_loadbalancer(
|
|
||||||
name=lb_name,
|
|
||||||
project_id=lbaas_spec.project_id,
|
|
||||||
subnet_id=lbaas_spec.subnet_id,
|
|
||||||
ip=lbaas_spec.ip,
|
|
||||||
security_groups_ids=lbaas_spec.security_groups_ids,
|
|
||||||
service_type=lbaas_spec.type,
|
|
||||||
provider=self._lb_provider)
|
|
||||||
changed = True
|
|
||||||
elif lbaas_state.service_pub_ip_info:
|
|
||||||
self._drv_service_pub_ip.release_pub_ip(
|
|
||||||
lbaas_state.service_pub_ip_info)
|
|
||||||
lbaas_state.service_pub_ip_info = None
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
lbaas_state.loadbalancer = lb
|
|
||||||
return changed
|
|
||||||
|
|
||||||
def _cleanup_leftover_lbaas(self):
|
|
||||||
lbaas_client = clients.get_loadbalancer_client()
|
|
||||||
services = []
|
|
||||||
try:
|
|
||||||
services = driver_utils.get_services().get('items')
|
|
||||||
except k_exc.K8sClientException:
|
|
||||||
LOG.debug("Skipping cleanup of leftover lbaas. "
|
|
||||||
"Error retriving Kubernetes services")
|
|
||||||
return
|
|
||||||
services_cluster_ip = {service['spec']['clusterIP']: service
|
|
||||||
for service in services
|
|
||||||
if service['spec'].get('clusterIP')}
|
|
||||||
|
|
||||||
services_without_selector = set(
|
|
||||||
service['spec']['clusterIP'] for service in services
|
|
||||||
if (service['spec'].get('clusterIP') and
|
|
||||||
not service['spec'].get('selector')))
|
|
||||||
lbaas_spec = {}
|
|
||||||
self._drv_lbaas.add_tags('loadbalancer', lbaas_spec)
|
|
||||||
loadbalancers = lbaas_client.load_balancers(**lbaas_spec)
|
|
||||||
for loadbalancer in loadbalancers:
|
|
||||||
if loadbalancer.vip_address not in services_cluster_ip.keys():
|
|
||||||
lb_obj = obj_lbaas.LBaaSLoadBalancer(**loadbalancer)
|
|
||||||
eventlet.spawn(self._ensure_release_lbaas, lb_obj)
|
|
||||||
else:
|
|
||||||
# check if the provider is the right one
|
|
||||||
if (loadbalancer.vip_address not in services_without_selector
|
|
||||||
and self._lb_provider
|
|
||||||
and self._lb_provider != loadbalancer.provider):
|
|
||||||
LOG.debug("Removing loadbalancer with old provider: %s",
|
|
||||||
loadbalancer)
|
|
||||||
lb_obj = obj_lbaas.LBaaSLoadBalancer(**loadbalancer)
|
|
||||||
eventlet.spawn(
|
|
||||||
self._ensure_release_lbaas,
|
|
||||||
lb_obj,
|
|
||||||
services_cluster_ip[loadbalancer.vip_address])
|
|
||||||
# NOTE(ltomasbo): give some extra time in between lbs
|
|
||||||
# recreation actions
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
def _ensure_release_lbaas(self, lb_obj, svc=None):
|
|
||||||
attempts = 0
|
|
||||||
deadline = 0
|
|
||||||
retry = True
|
|
||||||
timeout = config.CONF.kubernetes.watch_retry_timeout
|
|
||||||
while retry:
|
|
||||||
try:
|
|
||||||
if attempts == 1:
|
|
||||||
deadline = time.time() + timeout
|
|
||||||
if (attempts > 0 and
|
|
||||||
utils.exponential_sleep(deadline, attempts) == 0):
|
|
||||||
LOG.error("Failed releasing lbaas '%s': deadline exceeded",
|
|
||||||
lb_obj.name)
|
|
||||||
return
|
|
||||||
self._drv_lbaas.release_loadbalancer(lb_obj)
|
|
||||||
retry = False
|
|
||||||
except k_exc.ResourceNotReady:
|
|
||||||
LOG.debug("Attempt (%s) of loadbalancer release %s failed."
|
|
||||||
" A retry will be triggered.", attempts,
|
|
||||||
lb_obj.name)
|
|
||||||
attempts += 1
|
|
||||||
retry = True
|
|
||||||
if svc:
|
|
||||||
endpoints_link = utils.get_endpoints_link(svc)
|
|
||||||
k8s = clients.get_kubernetes_client()
|
|
||||||
try:
|
|
||||||
endpoints = k8s.get(endpoints_link)
|
|
||||||
except k_exc.K8sResourceNotFound:
|
|
||||||
LOG.debug("Endpoint not Found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
lbaas = utils.get_lbaas_state(endpoints)
|
|
||||||
if lbaas:
|
|
||||||
lbaas.loadbalancer = None
|
|
||||||
lbaas.pools = []
|
|
||||||
lbaas.listeners = []
|
|
||||||
lbaas.members = []
|
|
||||||
# NOTE(ltomasbo): give some extra time to ensure the Load
|
|
||||||
# Balancer VIP is also released
|
|
||||||
time.sleep(1)
|
|
||||||
utils.set_lbaas_state(endpoints, lbaas)
|
|
||||||
|
|
|
@ -0,0 +1,810 @@
|
||||||
|
# Copyright (c) 2020 Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import eventlet
|
||||||
|
import time
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from kuryr_kubernetes import clients
|
||||||
|
from kuryr_kubernetes import config
|
||||||
|
from kuryr_kubernetes import constants as k_const
|
||||||
|
from kuryr_kubernetes.controller.drivers import base as drv_base
|
||||||
|
from kuryr_kubernetes.controller.drivers import utils as driver_utils
|
||||||
|
from kuryr_kubernetes import exceptions as k_exc
|
||||||
|
from kuryr_kubernetes.handlers import k8s_base
|
||||||
|
from kuryr_kubernetes.objects import lbaas as obj_lbaas
|
||||||
|
from kuryr_kubernetes import utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
SUPPORTED_SERVICE_TYPES = ('ClusterIP', 'LoadBalancer')
|
||||||
|
|
||||||
|
|
||||||
|
class KuryrLoadBalancerHandler(k8s_base.ResourceEventHandler):
|
||||||
|
"""LoadBalancerStatusHandler handles K8s Endpoints events.
|
||||||
|
|
||||||
|
LBStatusHandler handles K8s Endpoints events and tracks changes in
|
||||||
|
LBaaSServiceSpec to update Neutron LBaaS accordingly and to reflect its'
|
||||||
|
actual state in LBaaSState.
|
||||||
|
"""
|
||||||
|
|
||||||
|
OBJECT_KIND = k_const.K8S_OBJ_KURYRLOADBALANCER
|
||||||
|
OBJECT_WATCH_PATH = k_const.K8S_API_CRD_KURYRLOADBALANCERS
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(KuryrLoadBalancerHandler, self).__init__()
|
||||||
|
self._drv_lbaas = drv_base.LBaaSDriver.get_instance()
|
||||||
|
self._drv_pod_project = drv_base.PodProjectDriver.get_instance()
|
||||||
|
self._drv_pod_subnets = drv_base.PodSubnetsDriver.get_instance()
|
||||||
|
self._drv_service_pub_ip = drv_base.ServicePubIpDriver.get_instance()
|
||||||
|
# Note(yboaron) LBaaS driver supports 'provider' parameter in
|
||||||
|
# Load Balancer creation flow.
|
||||||
|
# We need to set the requested load balancer provider
|
||||||
|
# according to 'endpoints_driver_octavia_provider' configuration.
|
||||||
|
self._lb_provider = None
|
||||||
|
if (config.CONF.kubernetes.endpoints_driver_octavia_provider
|
||||||
|
!= 'default'):
|
||||||
|
self._lb_provider = (
|
||||||
|
config.CONF.kubernetes.endpoints_driver_octavia_provider)
|
||||||
|
eventlet.spawn(self._cleanup_leftover_lbaas)
|
||||||
|
|
||||||
|
def on_present(self, loadbalancer_crd):
|
||||||
|
if self._should_ignore(loadbalancer_crd):
|
||||||
|
LOG.debug("Ignoring Kubernetes service %s",
|
||||||
|
loadbalancer_crd['metadata']['name'])
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
name = loadbalancer_crd['metadata']['name']
|
||||||
|
namespace = loadbalancer_crd['metadata']['namespace']
|
||||||
|
self._get_loadbalancer_crd(name, namespace)
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except KeyError:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found')
|
||||||
|
raise k_exc.ResourceNotReady(loadbalancer_crd)
|
||||||
|
|
||||||
|
if self._sync_lbaas_members(loadbalancer_crd):
|
||||||
|
# Note(yboaron) For LoadBalancer services, we should allocate FIP,
|
||||||
|
# associate it to LB VIP and update K8S service status
|
||||||
|
# if loadbalancer_crd['status'].get('service_pub_ip_info') is None:
|
||||||
|
lb_ip = loadbalancer_crd['spec'].get('lb_ip')
|
||||||
|
pub_info = loadbalancer_crd['status'].get(
|
||||||
|
'service_pub_ip_info')
|
||||||
|
if pub_info is None:
|
||||||
|
service_pub_ip_info = (
|
||||||
|
self._drv_service_pub_ip.acquire_service_pub_ip_info(
|
||||||
|
loadbalancer_crd['spec']['type'],
|
||||||
|
lb_ip,
|
||||||
|
loadbalancer_crd['spec']['project_id'],
|
||||||
|
loadbalancer_crd['status']['loadbalancer'][
|
||||||
|
'port_id']))
|
||||||
|
if service_pub_ip_info:
|
||||||
|
self._drv_service_pub_ip.associate_pub_ip(
|
||||||
|
service_pub_ip_info, loadbalancer_crd['status'][
|
||||||
|
'loadbalancer']['port_id'])
|
||||||
|
loadbalancer_crd['status'][
|
||||||
|
'service_pub_ip_info'] = service_pub_ip_info
|
||||||
|
self._update_lb_status(loadbalancer_crd)
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('status', loadbalancer_crd[
|
||||||
|
'metadata']['selfLink'], loadbalancer_crd[
|
||||||
|
'status'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _should_ignore(self, loadbalancer_crd):
|
||||||
|
return not(self._has_pods(loadbalancer_crd))
|
||||||
|
|
||||||
|
def _has_pods(self, loadbalancer_crd):
|
||||||
|
ep_subsets = loadbalancer_crd['spec'].get('subsets', [])
|
||||||
|
if not ep_subsets:
|
||||||
|
return False
|
||||||
|
return any(True
|
||||||
|
for subset in ep_subsets
|
||||||
|
for address in subset.get('addresses', [])
|
||||||
|
if address['targetRef'].get('kind', []) == 'Pod')
|
||||||
|
|
||||||
|
def on_finalize(self, loadbalancer_crd):
|
||||||
|
LOG.debug("Deleting the loadbalancer CRD")
|
||||||
|
|
||||||
|
if not loadbalancer_crd:
|
||||||
|
LOG.warning("Load Balancer CRD not present")
|
||||||
|
return
|
||||||
|
|
||||||
|
if loadbalancer_crd['status'] != {}:
|
||||||
|
# NOTE(ivc): deleting pool deletes its members
|
||||||
|
self._drv_lbaas.release_loadbalancer(
|
||||||
|
loadbalancer=loadbalancer_crd['status'].get('loadbalancer'))
|
||||||
|
|
||||||
|
try:
|
||||||
|
pub_info = loadbalancer_crd['status']['service_pub_ip_info']
|
||||||
|
except KeyError:
|
||||||
|
pub_info = None
|
||||||
|
|
||||||
|
if pub_info:
|
||||||
|
self._drv_service_pub_ip.release_pub_ip(
|
||||||
|
loadbalancer_crd['status']['service_pub_ip_info'])
|
||||||
|
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
LOG.debug('Removing finalizer from KuryrLoadBalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
try:
|
||||||
|
kubernetes.remove_finalizer(loadbalancer_crd,
|
||||||
|
k_const.KURYRLB_FINALIZER)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error removing kuryrloadbalancer CRD finalizer'
|
||||||
|
'for %s', loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
|
||||||
|
namespace = loadbalancer_crd['metadata']['namespace']
|
||||||
|
name = loadbalancer_crd['metadata']['name']
|
||||||
|
try:
|
||||||
|
service = kubernetes.get(f"{k_const.K8S_API_NAMESPACES}"
|
||||||
|
f"/{namespace}/services/{name}")
|
||||||
|
except k_exc.K8sResourceNotFound as ex:
|
||||||
|
LOG.exception("Failed to get service: %s", ex)
|
||||||
|
raise
|
||||||
|
|
||||||
|
LOG.debug('Removing finalizer from service %s',
|
||||||
|
service["metadata"]["name"])
|
||||||
|
try:
|
||||||
|
kubernetes.remove_finalizer(service, k_const.SERVICE_FINALIZER)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error removing service finalizer'
|
||||||
|
'for %s', service["metadata"]["name"])
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _get_loadbalancer_crd(self, loadbalancer_crd_name, namespace):
|
||||||
|
k8s = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
loadbalancer_crd = k8s.get('{}/{}/kuryrloadbalancers/{}'.format(
|
||||||
|
k_const.K8S_API_CRD_NAMESPACES, namespace,
|
||||||
|
loadbalancer_crd_name))
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
return None
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception("Kubernetes Client Exception.")
|
||||||
|
raise
|
||||||
|
return loadbalancer_crd
|
||||||
|
|
||||||
|
def _sync_lbaas_members(self, loadbalancer_crd):
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
if (self._has_pods(loadbalancer_crd) and
|
||||||
|
self._remove_unused_members(loadbalancer_crd)):
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if self._sync_lbaas_pools(loadbalancer_crd):
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if (self._has_pods(loadbalancer_crd) and
|
||||||
|
self._add_new_members(loadbalancer_crd)):
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
return changed
|
||||||
|
|
||||||
|
def _sync_lbaas_sgs(self, loadbalancer_crd):
|
||||||
|
# NOTE (maysams) Need to retrieve the LBaaS Spec again due to
|
||||||
|
# the possibility of it being updated after the LBaaS creation
|
||||||
|
# process has started.
|
||||||
|
lbaas_spec = loadbalancer_crd.get('spec')
|
||||||
|
|
||||||
|
lb = loadbalancer_crd['status'].get('loadbalancer')
|
||||||
|
if not lb:
|
||||||
|
return
|
||||||
|
|
||||||
|
default_sgs = config.CONF.neutron_defaults.pod_security_groups
|
||||||
|
# NOTE(maysams) As the endpoint and svc are annotated with the
|
||||||
|
# 'lbaas_spec' in two separate k8s calls, it's possible that
|
||||||
|
# the endpoint got annotated and the svc haven't due to controller
|
||||||
|
# restarts. For this case, a resourceNotReady exception is raised
|
||||||
|
# till the svc gets annotated with a 'lbaas_spec'.
|
||||||
|
if lbaas_spec:
|
||||||
|
lbaas_spec_sgs = loadbalancer_crd['spec'].get(
|
||||||
|
'security_groups_ids', [])
|
||||||
|
else:
|
||||||
|
raise k_exc.ResourceNotReady(lbaas_spec_sgs)
|
||||||
|
if (lb.get('security_groups') and
|
||||||
|
lb.get('security_groups') != lbaas_spec_sgs):
|
||||||
|
sgs = [lb_sg for lb_sg in lb['security_groups']
|
||||||
|
if lb_sg not in default_sgs]
|
||||||
|
if lbaas_spec_sgs != default_sgs:
|
||||||
|
sgs.extend(lbaas_spec_sgs)
|
||||||
|
|
||||||
|
# Check if this should update the CRD
|
||||||
|
lb['security_groups'] = sgs
|
||||||
|
|
||||||
|
def _add_new_members(self, loadbalancer_crd):
|
||||||
|
changed = False
|
||||||
|
try:
|
||||||
|
self._sync_lbaas_sgs(loadbalancer_crd)
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug("The svc has been deleted while processing the endpoints"
|
||||||
|
" update. No need to add new members.")
|
||||||
|
|
||||||
|
lsnr_by_id = {l['id']: l for l in loadbalancer_crd['status'].get(
|
||||||
|
'listeners', [])}
|
||||||
|
pool_by_lsnr_port = {(lsnr_by_id[p['listener_id']]['protocol'],
|
||||||
|
lsnr_by_id[p['listener_id']]['port']): p
|
||||||
|
for p in loadbalancer_crd['status'].get(
|
||||||
|
'pools', [])}
|
||||||
|
|
||||||
|
# NOTE(yboaron): Since LBaaSv2 doesn't support UDP load balancing,
|
||||||
|
# the LBaaS driver will return 'None' in case of UDP port
|
||||||
|
# listener creation.
|
||||||
|
# we should consider the case in which
|
||||||
|
# 'pool_by_lsnr_port[p.protocol, p.port]' is missing
|
||||||
|
pool_by_tgt_name = {}
|
||||||
|
for p in loadbalancer_crd['spec'].get('ports', []):
|
||||||
|
try:
|
||||||
|
pool_by_tgt_name[p['name']] = pool_by_lsnr_port[p['protocol'],
|
||||||
|
p['port']]
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
current_targets = {(str(m['ip']), m['port'], m['pool_id'])
|
||||||
|
for m in loadbalancer_crd['status'].get(
|
||||||
|
'members', [])}
|
||||||
|
|
||||||
|
for subset in loadbalancer_crd['spec']['subsets']:
|
||||||
|
subset_ports = subset.get('ports', [])
|
||||||
|
for subset_address in subset.get('addresses', []):
|
||||||
|
try:
|
||||||
|
target_ip = subset_address['ip']
|
||||||
|
target_ref = subset_address['targetRef']
|
||||||
|
if target_ref['kind'] != k_const.K8S_OBJ_POD:
|
||||||
|
continue
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
if not pool_by_tgt_name:
|
||||||
|
continue
|
||||||
|
for subset_port in subset_ports:
|
||||||
|
target_port = subset_port['port']
|
||||||
|
port_name = subset_port.get('name')
|
||||||
|
try:
|
||||||
|
pool = pool_by_tgt_name[port_name]
|
||||||
|
except KeyError:
|
||||||
|
LOG.debug("No pool found for port: %r", port_name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (target_ip, target_port, pool['id']) in current_targets:
|
||||||
|
continue
|
||||||
|
# TODO(apuimedo): Do not pass subnet_id at all when in
|
||||||
|
# L3 mode once old neutron-lbaasv2 is not supported, as
|
||||||
|
# octavia does not require it
|
||||||
|
if (config.CONF.octavia_defaults.member_mode ==
|
||||||
|
k_const.OCTAVIA_L2_MEMBER_MODE):
|
||||||
|
try:
|
||||||
|
member_subnet_id = self._get_pod_subnet(target_ref,
|
||||||
|
target_ip)
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug("Member namespace has been deleted. No "
|
||||||
|
"need to add the members as it is "
|
||||||
|
"going to be deleted")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# We use the service subnet id so that the connectivity
|
||||||
|
# from VIP to pods happens in layer 3 mode, i.e.,
|
||||||
|
# routed.
|
||||||
|
member_subnet_id = loadbalancer_crd['status'][
|
||||||
|
'loadbalancer']['subnet_id']
|
||||||
|
first_member_of_the_pool = True
|
||||||
|
for member in loadbalancer_crd['status'].get(
|
||||||
|
'members', []):
|
||||||
|
if pool['id'] == member['pool_id']:
|
||||||
|
first_member_of_the_pool = False
|
||||||
|
break
|
||||||
|
if first_member_of_the_pool:
|
||||||
|
listener_port = lsnr_by_id[pool['listener_id']][
|
||||||
|
'port']
|
||||||
|
else:
|
||||||
|
listener_port = None
|
||||||
|
loadbalancer = loadbalancer_crd['status']['loadbalancer']
|
||||||
|
member = self._drv_lbaas.ensure_member(
|
||||||
|
loadbalancer=loadbalancer,
|
||||||
|
pool=pool,
|
||||||
|
subnet_id=member_subnet_id,
|
||||||
|
ip=target_ip,
|
||||||
|
port=target_port,
|
||||||
|
target_ref_namespace=target_ref['namespace'],
|
||||||
|
target_ref_name=target_ref['name'],
|
||||||
|
listener_port=listener_port)
|
||||||
|
members = loadbalancer_crd['status'].get('members', [])
|
||||||
|
if members:
|
||||||
|
loadbalancer_crd['status'].get('members', []).append(
|
||||||
|
member)
|
||||||
|
else:
|
||||||
|
loadbalancer_crd['status']['members'] = []
|
||||||
|
loadbalancer_crd['status'].get('members', []).append(
|
||||||
|
member)
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('status', loadbalancer_crd[
|
||||||
|
'metadata']['selfLink'], loadbalancer_crd[
|
||||||
|
'status'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
changed = True
|
||||||
|
return changed
|
||||||
|
|
||||||
|
def _get_pod_subnet(self, target_ref, ip):
|
||||||
|
# REVISIT(ivc): consider using true pod object instead
|
||||||
|
pod = {'kind': target_ref['kind'],
|
||||||
|
'metadata': {'name': target_ref['name'],
|
||||||
|
'namespace': target_ref['namespace']}}
|
||||||
|
project_id = self._drv_pod_project.get_project(pod)
|
||||||
|
subnets_map = self._drv_pod_subnets.get_subnets(pod, project_id)
|
||||||
|
subnet_ids = [subnet_id for subnet_id, network in subnets_map.items()
|
||||||
|
for subnet in network.subnets.objects
|
||||||
|
if ip in subnet.cidr]
|
||||||
|
if subnet_ids:
|
||||||
|
return subnet_ids[0]
|
||||||
|
else:
|
||||||
|
# NOTE(ltomasbo): We are assuming that if ip is not on the
|
||||||
|
# pod subnet is because the member is using hostnetworking. In
|
||||||
|
# this worker_nodes_subnet will be used
|
||||||
|
return config.CONF.pod_vif_nested.worker_nodes_subnet
|
||||||
|
|
||||||
|
def _get_port_in_pool(self, pool, loadbalancer_crd):
|
||||||
|
|
||||||
|
for l in loadbalancer_crd['status']['listeners']:
|
||||||
|
if l['id'] != pool['listener_id']:
|
||||||
|
continue
|
||||||
|
for port in loadbalancer_crd['spec'].get('ports', []):
|
||||||
|
if l.get('port') == port.get(
|
||||||
|
'port') and l.get('protocol') == port.get('protocol'):
|
||||||
|
return port
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _remove_unused_members(self, loadbalancer_crd):
|
||||||
|
spec_ports = {}
|
||||||
|
pools = loadbalancer_crd['status'].get('pools', [])
|
||||||
|
for pool in pools:
|
||||||
|
port = self._get_port_in_pool(pool, loadbalancer_crd)
|
||||||
|
if port:
|
||||||
|
if not port.get('name'):
|
||||||
|
port['name'] = None
|
||||||
|
spec_ports[port['name']] = pool['id']
|
||||||
|
|
||||||
|
subsets = loadbalancer_crd['spec'].get('subsets')
|
||||||
|
current_targets = {(a['ip'], a.get('targetRef', {}).get('name', ''),
|
||||||
|
p['port'], spec_ports.get(p.get('name')))
|
||||||
|
for s in subsets
|
||||||
|
for a in s['addresses']
|
||||||
|
for p in s['ports']
|
||||||
|
if p.get('name') in spec_ports}
|
||||||
|
|
||||||
|
removed_ids = set()
|
||||||
|
|
||||||
|
for member in loadbalancer_crd['status'].get('members', []):
|
||||||
|
try:
|
||||||
|
member_name = member['name']
|
||||||
|
# NOTE: The member name is compose of:
|
||||||
|
# NAMESPACE_NAME/POD_NAME:PROTOCOL_PORT
|
||||||
|
pod_name = member_name.split('/')[1].split(':')[0]
|
||||||
|
except AttributeError:
|
||||||
|
pod_name = ""
|
||||||
|
if ((str(member['ip']), pod_name, member['port'], member[
|
||||||
|
'pool_id']) in current_targets):
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._drv_lbaas.release_member(loadbalancer_crd['status'][
|
||||||
|
'loadbalancer'], member)
|
||||||
|
removed_ids.add(member['id'])
|
||||||
|
|
||||||
|
if removed_ids:
|
||||||
|
loadbalancer_crd['status']['members'] = [m for m in
|
||||||
|
loadbalancer_crd[
|
||||||
|
'status'][
|
||||||
|
'members']
|
||||||
|
if m['id'] not in
|
||||||
|
removed_ids]
|
||||||
|
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('status', loadbalancer_crd[
|
||||||
|
'metadata']['selfLink'], loadbalancer_crd[
|
||||||
|
'status'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
return bool(removed_ids)
|
||||||
|
|
||||||
|
def _sync_lbaas_pools(self, loadbalancer_crd):
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
if self._remove_unused_pools(loadbalancer_crd):
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if self._sync_lbaas_listeners(loadbalancer_crd):
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if self._add_new_pools(loadbalancer_crd):
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
return changed
|
||||||
|
|
||||||
|
def _add_new_pools(self, loadbalancer_crd):
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
current_listeners_ids = {pool['listener_id']
|
||||||
|
for pool in loadbalancer_crd['status'].get(
|
||||||
|
'pools', [])}
|
||||||
|
for listener in loadbalancer_crd['status'].get('listeners', []):
|
||||||
|
if listener['id'] in current_listeners_ids:
|
||||||
|
continue
|
||||||
|
pool = self._drv_lbaas.ensure_pool(loadbalancer_crd['status'][
|
||||||
|
'loadbalancer'], listener)
|
||||||
|
pools = loadbalancer_crd['status'].get('pools', [])
|
||||||
|
if pools:
|
||||||
|
loadbalancer_crd['status'].get('pools', []).append(
|
||||||
|
pool)
|
||||||
|
else:
|
||||||
|
loadbalancer_crd['status']['pools'] = []
|
||||||
|
loadbalancer_crd['status'].get('pools', []).append(
|
||||||
|
pool)
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('status', loadbalancer_crd['metadata'][
|
||||||
|
'selfLink'], loadbalancer_crd['status'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryrLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
changed = True
|
||||||
|
return changed
|
||||||
|
|
||||||
|
def _is_pool_in_spec(self, pool, loadbalancer_crd):
|
||||||
|
# NOTE(yboaron): in order to check if a specific pool is in lbaas_spec
|
||||||
|
# we should:
|
||||||
|
# 1. get the listener that pool is attached to
|
||||||
|
# 2. check if listener's attributes appear in lbaas_spec.
|
||||||
|
for l in loadbalancer_crd['status']['listeners']:
|
||||||
|
if l['id'] != pool['listener_id']:
|
||||||
|
continue
|
||||||
|
for port in loadbalancer_crd['spec'].get('ports'):
|
||||||
|
if l['port'] == port['port'] and l['protocol'] == port[
|
||||||
|
'protocol']:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _remove_unused_pools(self, loadbalancer_crd):
|
||||||
|
removed_ids = set()
|
||||||
|
|
||||||
|
for pool in loadbalancer_crd['status'].get('pools', []):
|
||||||
|
if self._is_pool_in_spec(pool, loadbalancer_crd):
|
||||||
|
continue
|
||||||
|
self._drv_lbaas.release_pool(loadbalancer_crd['status'][
|
||||||
|
'loadbalancer'], pool)
|
||||||
|
removed_ids.add(pool['id'])
|
||||||
|
if removed_ids:
|
||||||
|
loadbalancer_crd['status']['pools'] = [p for p in loadbalancer_crd[
|
||||||
|
'status']['pools'] if p['id'] not in removed_ids]
|
||||||
|
loadbalancer_crd['status']['members'] = [m for m in
|
||||||
|
loadbalancer_crd[
|
||||||
|
'status']['members']
|
||||||
|
if m['pool_id'] not in
|
||||||
|
removed_ids]
|
||||||
|
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('status', loadbalancer_crd[
|
||||||
|
'metadata']['selfLink'], loadbalancer_crd[
|
||||||
|
'status'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
return bool(removed_ids)
|
||||||
|
|
||||||
|
def _sync_lbaas_listeners(self, loadbalancer_crd):
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
if self._remove_unused_listeners(loadbalancer_crd):
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if self._sync_lbaas_loadbalancer(loadbalancer_crd):
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if self._add_new_listeners(loadbalancer_crd):
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
return changed
|
||||||
|
|
||||||
|
def _add_new_listeners(self, loadbalancer_crd):
|
||||||
|
changed = False
|
||||||
|
lb_crd_spec_ports = loadbalancer_crd['spec'].get('ports')
|
||||||
|
if not lb_crd_spec_ports:
|
||||||
|
return changed
|
||||||
|
lbaas_spec_ports = sorted(lb_crd_spec_ports,
|
||||||
|
key=lambda x: x['protocol'])
|
||||||
|
for port_spec in lbaas_spec_ports:
|
||||||
|
protocol = port_spec['protocol']
|
||||||
|
port = port_spec['port']
|
||||||
|
name = "%s:%s" % (loadbalancer_crd['status']['loadbalancer'][
|
||||||
|
'name'], protocol)
|
||||||
|
|
||||||
|
listener = [l for l in loadbalancer_crd['status'].get(
|
||||||
|
'listeners', []) if l['port'] == port and l[
|
||||||
|
'protocol'] == protocol]
|
||||||
|
|
||||||
|
if listener:
|
||||||
|
continue
|
||||||
|
# FIXME (maysams): Due to a bug in Octavia, which does
|
||||||
|
# not allows listeners with same port but different
|
||||||
|
# protocols to co-exist, we need to skip the creation of
|
||||||
|
# listeners that have the same port as an existing one.
|
||||||
|
listener = [l for l in loadbalancer_crd['status'].get(
|
||||||
|
'listeners', []) if l['port'] == port]
|
||||||
|
|
||||||
|
if listener and not self._drv_lbaas.double_listeners_supported():
|
||||||
|
LOG.warning("Skipping listener creation for %s as another one"
|
||||||
|
" already exists with port %s", name, port)
|
||||||
|
continue
|
||||||
|
listener = self._drv_lbaas.ensure_listener(
|
||||||
|
loadbalancer=loadbalancer_crd['status'].get('loadbalancer'),
|
||||||
|
protocol=protocol,
|
||||||
|
port=port,
|
||||||
|
service_type=loadbalancer_crd['spec'].get('type'))
|
||||||
|
if listener is not None:
|
||||||
|
listeners = loadbalancer_crd['status'].get('listeners', [])
|
||||||
|
if listeners:
|
||||||
|
listeners.append(listener)
|
||||||
|
else:
|
||||||
|
loadbalancer_crd['status']['listeners'] = []
|
||||||
|
loadbalancer_crd['status'].get('listeners', []).append(
|
||||||
|
listener)
|
||||||
|
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('status', loadbalancer_crd[
|
||||||
|
'metadata']['selfLink'], loadbalancer_crd['status'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryrLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
changed = True
|
||||||
|
return changed
|
||||||
|
|
||||||
|
def _remove_unused_listeners(self, loadbalancer_crd):
|
||||||
|
current_listeners = {p['listener_id'] for p in loadbalancer_crd[
|
||||||
|
'status'].get('pools', [])}
|
||||||
|
removed_ids = set()
|
||||||
|
for listener in loadbalancer_crd['status'].get('listeners', []):
|
||||||
|
if listener['id'] in current_listeners:
|
||||||
|
continue
|
||||||
|
self._drv_lbaas.release_listener(loadbalancer_crd['status'][
|
||||||
|
'loadbalancer'], listener)
|
||||||
|
removed_ids.add(listener['id'])
|
||||||
|
if removed_ids:
|
||||||
|
loadbalancer_crd['status']['listeners'] = [
|
||||||
|
l for l in loadbalancer_crd['status'].get('listeners',
|
||||||
|
[]) if l['id']
|
||||||
|
not in removed_ids]
|
||||||
|
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('status', loadbalancer_crd[
|
||||||
|
'metadata']['selfLink'], loadbalancer_crd[
|
||||||
|
'status'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
return bool(removed_ids)
|
||||||
|
|
||||||
|
def _update_lb_status(self, lb_crd):
|
||||||
|
lb_crd_status = lb_crd['status']
|
||||||
|
lb_ip_address = lb_crd_status['service_pub_ip_info']['ip_addr']
|
||||||
|
name = lb_crd['metadata']['name']
|
||||||
|
ns = lb_crd['metadata']['namespace']
|
||||||
|
status_data = {"loadBalancer": {
|
||||||
|
"ingress": [{"ip": lb_ip_address.format()}]}}
|
||||||
|
k8s = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
k8s.patch("status", f"{k_const.K8S_API_NAMESPACES}"
|
||||||
|
f"/{ns}/services/{name}/status",
|
||||||
|
status_data)
|
||||||
|
except k_exc.K8sConflict:
|
||||||
|
raise k_exc.ResourceNotReady(name)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception("Kubernetes Client Exception"
|
||||||
|
"when updating the svc status %s"
|
||||||
|
% name)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _sync_lbaas_loadbalancer(self, loadbalancer_crd):
|
||||||
|
changed = False
|
||||||
|
lb = loadbalancer_crd['status'].get('loadbalancer')
|
||||||
|
|
||||||
|
if lb and lb['ip'] != loadbalancer_crd['spec'].get('ip'):
|
||||||
|
# if loadbalancerIP was associated to lbaas VIP, disassociate it.
|
||||||
|
|
||||||
|
try:
|
||||||
|
pub_info = loadbalancer_crd['status']['service_pub_ip_info']
|
||||||
|
except KeyError:
|
||||||
|
pub_info = None
|
||||||
|
|
||||||
|
if pub_info:
|
||||||
|
self._drv_service_pub_ip.disassociate_pub_ip(
|
||||||
|
loadbalancer_crd['status']['service_pub_ip_info'])
|
||||||
|
|
||||||
|
self._drv_lbaas.release_loadbalancer(
|
||||||
|
loadbalancer=lb)
|
||||||
|
lb = None
|
||||||
|
loadbalancer_crd['status']['pools'] = []
|
||||||
|
loadbalancer_crd['status']['listeners'] = []
|
||||||
|
loadbalancer_crd['status']['members'] = []
|
||||||
|
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('status', loadbalancer_crd['metadata'][
|
||||||
|
'selfLink'], loadbalancer_crd['status'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryrLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if not lb:
|
||||||
|
if loadbalancer_crd['spec'].get('ip'):
|
||||||
|
lb_name = self._drv_lbaas.get_service_loadbalancer_name(
|
||||||
|
loadbalancer_crd['metadata']['namespace'],
|
||||||
|
loadbalancer_crd['metadata']['name'])
|
||||||
|
lb = self._drv_lbaas.ensure_loadbalancer(
|
||||||
|
name=lb_name,
|
||||||
|
project_id=loadbalancer_crd['spec'].get('project_id'),
|
||||||
|
subnet_id=loadbalancer_crd['spec'].get('subnet_id'),
|
||||||
|
ip=loadbalancer_crd['spec'].get('ip'),
|
||||||
|
security_groups_ids=loadbalancer_crd['spec'].get(
|
||||||
|
'security_groups_ids'),
|
||||||
|
service_type=loadbalancer_crd['spec'].get('type'),
|
||||||
|
provider=self._lb_provider)
|
||||||
|
loadbalancer_crd['status']['loadbalancer'] = lb
|
||||||
|
changed = True
|
||||||
|
elif loadbalancer_crd['status'].get('service_pub_ip_info'):
|
||||||
|
self._drv_service_pub_ip.release_pub_ip(
|
||||||
|
loadbalancer_crd['status']['service_pub_ip_info'])
|
||||||
|
loadbalancer_crd['status']['service_pub_ip_info'] = None
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
kubernetes = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
kubernetes.patch_crd('status', loadbalancer_crd['metadata'][
|
||||||
|
'selfLink'], loadbalancer_crd['status'])
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug('KuryrLoadbalancer CRD not found %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.exception('Error updating KuryrLoadbalancer CRD %s',
|
||||||
|
loadbalancer_crd)
|
||||||
|
raise
|
||||||
|
|
||||||
|
return changed
|
||||||
|
|
||||||
|
def _cleanup_leftover_lbaas(self):
|
||||||
|
lbaas_client = clients.get_loadbalancer_client()
|
||||||
|
services = []
|
||||||
|
try:
|
||||||
|
services = driver_utils.get_services().get('items')
|
||||||
|
except k_exc.K8sClientException:
|
||||||
|
LOG.debug("Skipping cleanup of leftover lbaas. "
|
||||||
|
"Error retriving Kubernetes services")
|
||||||
|
return
|
||||||
|
services_cluster_ip = {service['spec']['clusterIP']: service
|
||||||
|
for service in services
|
||||||
|
if service['spec'].get('clusterIP')}
|
||||||
|
|
||||||
|
services_without_selector = set(
|
||||||
|
service['spec']['clusterIP'] for service in services
|
||||||
|
if (service['spec'].get('clusterIP') and
|
||||||
|
not service['spec'].get('selector')))
|
||||||
|
lbaas_spec = {}
|
||||||
|
self._drv_lbaas.add_tags('loadbalancer', lbaas_spec)
|
||||||
|
loadbalancers = lbaas_client.load_balancers(**lbaas_spec)
|
||||||
|
for loadbalancer in loadbalancers:
|
||||||
|
if loadbalancer.vip_address not in services_cluster_ip.keys():
|
||||||
|
lb_obj = obj_lbaas.LBaaSLoadBalancer(**loadbalancer)
|
||||||
|
eventlet.spawn(self._ensure_release_lbaas, lb_obj)
|
||||||
|
else:
|
||||||
|
# check if the provider is the right one
|
||||||
|
if (loadbalancer.vip_address not in services_without_selector
|
||||||
|
and self._lb_provider
|
||||||
|
and self._lb_provider != loadbalancer.provider):
|
||||||
|
LOG.debug("Removing loadbalancer with old provider: %s",
|
||||||
|
loadbalancer)
|
||||||
|
lb_obj = obj_lbaas.LBaaSLoadBalancer(**loadbalancer)
|
||||||
|
eventlet.spawn(
|
||||||
|
self._ensure_release_lbaas,
|
||||||
|
lb_obj,
|
||||||
|
services_cluster_ip[loadbalancer.vip_address])
|
||||||
|
# NOTE(ltomasbo): give some extra time in between lbs
|
||||||
|
# recreation actions
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def _ensure_release_lbaas(self, lb_obj, svc=None):
|
||||||
|
attempts = 0
|
||||||
|
deadline = 0
|
||||||
|
retry = True
|
||||||
|
timeout = config.CONF.kubernetes.watch_retry_timeout
|
||||||
|
while retry:
|
||||||
|
try:
|
||||||
|
if attempts == 1:
|
||||||
|
deadline = time.time() + timeout
|
||||||
|
if (attempts > 0 and
|
||||||
|
utils.exponential_sleep(deadline, attempts) == 0):
|
||||||
|
LOG.error("Failed releasing lbaas '%s': deadline exceeded",
|
||||||
|
lb_obj.name)
|
||||||
|
return
|
||||||
|
self._drv_lbaas.release_loadbalancer(lb_obj)
|
||||||
|
retry = False
|
||||||
|
except k_exc.ResourceNotReady:
|
||||||
|
LOG.debug("Attempt (%s) of loadbalancer release %s failed."
|
||||||
|
" A retry will be triggered.", attempts,
|
||||||
|
lb_obj.name)
|
||||||
|
attempts += 1
|
||||||
|
retry = True
|
||||||
|
if svc:
|
||||||
|
endpoints_link = utils.get_endpoints_link(svc)
|
||||||
|
k8s = clients.get_kubernetes_client()
|
||||||
|
try:
|
||||||
|
endpoints = k8s.get(endpoints_link)
|
||||||
|
except k_exc.K8sResourceNotFound:
|
||||||
|
LOG.debug("Endpoint not Found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
lbaas = utils.get_lbaas_state(endpoints)
|
||||||
|
if lbaas:
|
||||||
|
lbaas.loadbalancer = None
|
||||||
|
lbaas.pools = []
|
||||||
|
lbaas.listeners = []
|
||||||
|
lbaas.members = []
|
||||||
|
# NOTE(ltomasbo): give some extra time to ensure the Load
|
||||||
|
# Balancer VIP is also released
|
||||||
|
time.sleep(1)
|
||||||
|
utils.set_lbaas_state(endpoints, lbaas)
|
|
@ -293,6 +293,21 @@ class K8sClient(object):
|
||||||
# If after 3 iterations there's still conflict, just raise.
|
# If after 3 iterations there's still conflict, just raise.
|
||||||
self._raise_from_response(response)
|
self._raise_from_response(response)
|
||||||
|
|
||||||
|
def get_loadbalancer_crd(self, obj):
|
||||||
|
name = obj['metadata']['name']
|
||||||
|
namespace = obj['metadata']['namespace']
|
||||||
|
|
||||||
|
try:
|
||||||
|
crd = self.get('{}/{}/kuryrloadbalancers/{}'.format(
|
||||||
|
constants.K8S_API_CRD_NAMESPACES, namespace,
|
||||||
|
name))
|
||||||
|
except exc.K8sResourceNotFound:
|
||||||
|
return None
|
||||||
|
except exc.K8sClientException:
|
||||||
|
LOG.exception("Kubernetes Client Exception.")
|
||||||
|
raise
|
||||||
|
return crd
|
||||||
|
|
||||||
def annotate(self, path, annotations, resource_version=None):
|
def annotate(self, path, annotations, resource_version=None):
|
||||||
"""Pushes a resource annotation to the K8s API resource
|
"""Pushes a resource annotation to the K8s API resource
|
||||||
|
|
||||||
|
|
|
@ -53,10 +53,11 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
spec_type = 'LoadBalancer'
|
spec_type = 'LoadBalancer'
|
||||||
spec_lb_ip = '1.2.3.4'
|
spec_lb_ip = '1.2.3.4'
|
||||||
|
|
||||||
expected_resp = (obj_lbaas
|
expected_resp = {
|
||||||
.LBaaSPubIp(ip_id=fip.id,
|
'ip_id': fip.id,
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_addr': fip.floating_ip_address,
|
||||||
alloc_method='user'))
|
'alloc_method': 'user'
|
||||||
|
}
|
||||||
|
|
||||||
result = cls.acquire_service_pub_ip_info(m_driver, spec_type,
|
result = cls.acquire_service_pub_ip_info(m_driver, spec_type,
|
||||||
spec_lb_ip, project_id)
|
spec_lb_ip, project_id)
|
||||||
|
@ -134,9 +135,11 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
spec_type = 'LoadBalancer'
|
spec_type = 'LoadBalancer'
|
||||||
spec_lb_ip = None
|
spec_lb_ip = None
|
||||||
|
|
||||||
expected_resp = obj_lbaas.LBaaSPubIp(ip_id=fip.id,
|
expected_resp = {
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_id': fip.id,
|
||||||
alloc_method='pool')
|
'ip_addr': fip.floating_ip_address,
|
||||||
|
'alloc_method': 'pool'
|
||||||
|
}
|
||||||
|
|
||||||
result = cls.acquire_service_pub_ip_info(m_driver, spec_type,
|
result = cls.acquire_service_pub_ip_info(m_driver, spec_type,
|
||||||
spec_lb_ip, project_id)
|
spec_lb_ip, project_id)
|
||||||
|
@ -161,9 +164,11 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
spec_type = 'LoadBalancer'
|
spec_type = 'LoadBalancer'
|
||||||
spec_lb_ip = None
|
spec_lb_ip = None
|
||||||
|
|
||||||
expected_resp = obj_lbaas.LBaaSPubIp(ip_id=fip.id,
|
expected_resp = {
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_id': fip.id,
|
||||||
alloc_method='pool')
|
'ip_addr': fip.floating_ip_address,
|
||||||
|
'alloc_method': 'pool'
|
||||||
|
}
|
||||||
|
|
||||||
result = cls.acquire_service_pub_ip_info(m_driver, spec_type,
|
result = cls.acquire_service_pub_ip_info(m_driver, spec_type,
|
||||||
spec_lb_ip, project_id)
|
spec_lb_ip, project_id)
|
||||||
|
@ -184,10 +189,11 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
||||||
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
||||||
|
|
||||||
service_pub_ip_info = (obj_lbaas
|
service_pub_ip_info = {
|
||||||
.LBaaSPubIp(ip_id=fip.id,
|
'ip_id': fip.id,
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_addr': fip.floating_ip_address,
|
||||||
alloc_method='kk'))
|
'alloc_method': 'kk'
|
||||||
|
}
|
||||||
|
|
||||||
rc = cls.release_pub_ip(m_driver, service_pub_ip_info)
|
rc = cls.release_pub_ip(m_driver, service_pub_ip_info)
|
||||||
self.assertIs(rc, True)
|
self.assertIs(rc, True)
|
||||||
|
@ -199,10 +205,12 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
||||||
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
||||||
|
|
||||||
service_pub_ip_info = (obj_lbaas
|
service_pub_ip_info = {
|
||||||
.LBaaSPubIp(ip_id=fip.id,
|
'ip_id': fip.id,
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_addr': fip.floating_ip_address,
|
||||||
alloc_method='user'))
|
'alloc_method': 'user'
|
||||||
|
}
|
||||||
|
|
||||||
rc = cls.release_pub_ip(m_driver, service_pub_ip_info)
|
rc = cls.release_pub_ip(m_driver, service_pub_ip_info)
|
||||||
self.assertIs(rc, True)
|
self.assertIs(rc, True)
|
||||||
|
|
||||||
|
@ -216,10 +224,11 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
||||||
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
||||||
|
|
||||||
service_pub_ip_info = (obj_lbaas
|
service_pub_ip_info = {
|
||||||
.LBaaSPubIp(ip_id=fip.id,
|
'ip_id': fip.id,
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_addr': fip.floating_ip_address,
|
||||||
alloc_method='pool'))
|
'alloc_method': 'pool'
|
||||||
|
}
|
||||||
rc = cls.release_pub_ip(m_driver, service_pub_ip_info)
|
rc = cls.release_pub_ip(m_driver, service_pub_ip_info)
|
||||||
self.assertIs(rc, False)
|
self.assertIs(rc, False)
|
||||||
|
|
||||||
|
@ -232,10 +241,11 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
||||||
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
||||||
|
|
||||||
service_pub_ip_info = (obj_lbaas
|
service_pub_ip_info = {
|
||||||
.LBaaSPubIp(ip_id=fip.id,
|
'ip_id': fip.id,
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_addr': fip.floating_ip_address,
|
||||||
alloc_method='pool'))
|
'alloc_method': 'pool'
|
||||||
|
}
|
||||||
rc = cls.release_pub_ip(m_driver, service_pub_ip_info)
|
rc = cls.release_pub_ip(m_driver, service_pub_ip_info)
|
||||||
self.assertIs(rc, True)
|
self.assertIs(rc, True)
|
||||||
|
|
||||||
|
@ -265,6 +275,11 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
.LBaaSPubIp(ip_id=0,
|
.LBaaSPubIp(ip_id=0,
|
||||||
ip_addr=fip.floating_ip_address,
|
ip_addr=fip.floating_ip_address,
|
||||||
alloc_method='pool'))
|
alloc_method='pool'))
|
||||||
|
service_pub_ip_info = {
|
||||||
|
'ip_id': 0,
|
||||||
|
'ip_addr': fip.floating_ip_address,
|
||||||
|
'alloc_method': 'pool'
|
||||||
|
}
|
||||||
|
|
||||||
vip_port_id = 'ec29d641-fec4-4f67-928a-124a76b3a777'
|
vip_port_id = 'ec29d641-fec4-4f67-928a-124a76b3a777'
|
||||||
|
|
||||||
|
@ -281,10 +296,12 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
|
|
||||||
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
||||||
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
||||||
service_pub_ip_info = (obj_lbaas
|
|
||||||
.LBaaSPubIp(ip_id=fip.id,
|
service_pub_ip_info = {
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_id': fip.id,
|
||||||
alloc_method='pool'))
|
'ip_addr': fip.floating_ip_address,
|
||||||
|
'alloc_method': 'pool'
|
||||||
|
}
|
||||||
vip_port_id = 'ec29d641-fec4-4f67-928a-124a76b3a777'
|
vip_port_id = 'ec29d641-fec4-4f67-928a-124a76b3a777'
|
||||||
|
|
||||||
self.assertRaises(os_exc.SDKException, cls.associate_pub_ip,
|
self.assertRaises(os_exc.SDKException, cls.associate_pub_ip,
|
||||||
|
@ -308,10 +325,11 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
os_net.update_floatingip.return_value = None
|
os_net.update_floatingip.return_value = None
|
||||||
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
||||||
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
||||||
service_pub_ip_info = (obj_lbaas
|
service_pub_ip_info = {
|
||||||
.LBaaSPubIp(ip_id=0,
|
'ip_id': 0,
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_addr': fip.floating_ip_address,
|
||||||
alloc_method='pool'))
|
'alloc_method': 'pool'
|
||||||
|
}
|
||||||
|
|
||||||
result = cls.disassociate_pub_ip(m_driver, service_pub_ip_info)
|
result = cls.disassociate_pub_ip(m_driver, service_pub_ip_info)
|
||||||
|
|
||||||
|
@ -325,10 +343,12 @@ class TestFloatingIpServicePubIPDriverDriver(test_base.TestCase):
|
||||||
os_net.update_ip.side_effect = os_exc.SDKException
|
os_net.update_ip.side_effect = os_exc.SDKException
|
||||||
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
fip = munch.Munch({'floating_ip_address': '1.2.3.5',
|
||||||
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'})
|
||||||
service_pub_ip_info = (obj_lbaas
|
|
||||||
.LBaaSPubIp(ip_id=fip.id,
|
service_pub_ip_info = {
|
||||||
ip_addr=fip.floating_ip_address,
|
'ip_id': fip.id,
|
||||||
alloc_method='pool'))
|
'ip_addr': fip.floating_ip_address,
|
||||||
|
'alloc_method': 'pool'
|
||||||
|
}
|
||||||
|
|
||||||
self.assertRaises(os_exc.SDKException, cls.disassociate_pub_ip,
|
self.assertRaises(os_exc.SDKException, cls.disassociate_pub_ip,
|
||||||
m_driver, service_pub_ip_info)
|
m_driver, service_pub_ip_info)
|
||||||
|
|
|
@ -112,9 +112,11 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
os_net = self.useFixture(k_fix.MockNetworkClient()).client
|
os_net = self.useFixture(k_fix.MockNetworkClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
expected_resp = obj_lbaas.LBaaSLoadBalancer(
|
expected_resp = {
|
||||||
provider='octavia', port_id='D3FA400A-F543-4B91-9CD3-047AF0CE42E2',
|
'provide': 'octavia',
|
||||||
security_groups=[])
|
'port_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42E2',
|
||||||
|
'security_groups': []
|
||||||
|
}
|
||||||
project_id = 'TEST_PROJECT'
|
project_id = 'TEST_PROJECT'
|
||||||
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
|
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
|
||||||
ip = '1.2.3.4'
|
ip = '1.2.3.4'
|
||||||
|
@ -129,10 +131,10 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
m_driver._find_loadbalancer,
|
m_driver._find_loadbalancer,
|
||||||
mock.ANY)
|
mock.ANY)
|
||||||
req = m_driver._ensure.call_args[0][2]
|
req = m_driver._ensure.call_args[0][2]
|
||||||
self.assertEqual(lb_name, req.name)
|
self.assertEqual(lb_name, req['name'])
|
||||||
self.assertEqual(project_id, req.project_id)
|
self.assertEqual(project_id, req['project_id'])
|
||||||
self.assertEqual(subnet_id, req.subnet_id)
|
self.assertEqual(subnet_id, req['subnet_id'])
|
||||||
self.assertEqual(ip, str(req.ip))
|
self.assertEqual(ip, str(req['ip']))
|
||||||
self.assertEqual(expected_resp, resp)
|
self.assertEqual(expected_resp, resp)
|
||||||
os_net.update_port.assert_not_called()
|
os_net.update_port.assert_not_called()
|
||||||
|
|
||||||
|
@ -157,29 +159,38 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
lbaas.lbaas_loadbalancer_path = "boo %s"
|
lbaas.lbaas_loadbalancer_path = "boo %s"
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = mock.Mock()
|
loadbalancer = {
|
||||||
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'security_groups': [],
|
||||||
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'provider': None
|
||||||
|
}
|
||||||
|
|
||||||
cls.release_loadbalancer(m_driver, loadbalancer)
|
cls.release_loadbalancer(m_driver, loadbalancer)
|
||||||
|
|
||||||
m_driver._release.assert_called_once_with(
|
m_driver._release.assert_called_once_with(
|
||||||
loadbalancer, loadbalancer, lbaas.delete_load_balancer,
|
loadbalancer, loadbalancer, lbaas.delete_load_balancer,
|
||||||
loadbalancer.id, cascade=True)
|
loadbalancer['id'], cascade=True)
|
||||||
|
|
||||||
def _test_ensure_listener(self):
|
def _test_ensure_listener(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
expected_resp = mock.sentinel.expected_resp
|
expected_resp = mock.sentinel.expected_resp
|
||||||
name = 'TEST_NAME'
|
|
||||||
project_id = 'TEST_PROJECT'
|
project_id = 'TEST_PROJECT'
|
||||||
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
|
|
||||||
ip = '1.2.3.4'
|
|
||||||
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
||||||
protocol = 'TCP'
|
protocol = 'TCP'
|
||||||
provider = 'amphora'
|
|
||||||
port = 1234
|
port = 1234
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
id=loadbalancer_id, name=name, project_id=project_id,
|
'name': 'TEST_NAME',
|
||||||
subnet_id=subnet_id, ip=ip, provider=provider)
|
'project_id': project_id,
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'provider': 'amphora'
|
||||||
|
}
|
||||||
# TODO(ivc): handle security groups
|
# TODO(ivc): handle security groups
|
||||||
m_driver._ensure_provisioned.return_value = expected_resp
|
m_driver._ensure_provisioned.return_value = expected_resp
|
||||||
|
|
||||||
|
@ -191,28 +202,27 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
m_driver._find_listener, d_lbaasv2._LB_STS_POLL_SLOW_INTERVAL)
|
m_driver._find_listener, d_lbaasv2._LB_STS_POLL_SLOW_INTERVAL)
|
||||||
listener = m_driver._ensure_provisioned.call_args[0][1]
|
listener = m_driver._ensure_provisioned.call_args[0][1]
|
||||||
|
|
||||||
self.assertEqual("%s:%s:%s" % (loadbalancer.name, protocol, port),
|
self.assertEqual("%s:%s:%s" % (loadbalancer['name'], protocol, port),
|
||||||
listener.name)
|
listener['name'])
|
||||||
self.assertEqual(project_id, listener.project_id)
|
self.assertEqual(project_id, listener['project_id'])
|
||||||
self.assertEqual(loadbalancer_id, listener.loadbalancer_id)
|
self.assertEqual(loadbalancer_id, listener['loadbalancer_id'])
|
||||||
self.assertEqual(protocol, listener.protocol)
|
self.assertEqual(protocol, listener['protocol'])
|
||||||
self.assertEqual(port, listener.port)
|
self.assertEqual(port, listener['port'])
|
||||||
self.assertEqual(expected_resp, resp)
|
self.assertEqual(expected_resp, resp)
|
||||||
|
|
||||||
def test_ensure_listener_bad_request_exception(self):
|
def test_ensure_listener_bad_request_exception(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
name = 'TEST_NAME'
|
|
||||||
project_id = 'TEST_PROJECT'
|
|
||||||
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
|
|
||||||
ip = '1.2.3.4'
|
|
||||||
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
|
||||||
port = 1234
|
port = 1234
|
||||||
protocol = 'TCP'
|
protocol = 'TCP'
|
||||||
provider = 'amphora'
|
loadbalancer = {
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
'name': 'TEST_NAME',
|
||||||
id=loadbalancer_id, name=name, project_id=project_id,
|
'project_id': 'TEST_PROJECT',
|
||||||
subnet_id=subnet_id, ip=ip, provider=provider)
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'provider': 'amphora'
|
||||||
|
}
|
||||||
m_driver._ensure_provisioned.side_effect = os_exc.BadRequestException
|
m_driver._ensure_provisioned.side_effect = os_exc.BadRequestException
|
||||||
|
|
||||||
resp = cls.ensure_listener(m_driver, loadbalancer,
|
resp = cls.ensure_listener(m_driver, loadbalancer,
|
||||||
|
@ -227,26 +237,43 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
m_driver._get_vip_port.return_value = munch.Munch({
|
m_driver._get_vip_port.return_value = munch.Munch({
|
||||||
'security_group_ids': [mock.sentinel.sg_id]})
|
'security_group_ids': [mock.sentinel.sg_id]})
|
||||||
loadbalancer = mock.Mock()
|
loadbalancer = {
|
||||||
listener = mock.Mock()
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'security_groups': [],
|
||||||
|
'provider': 'amphora'
|
||||||
|
}
|
||||||
|
listener = {
|
||||||
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 1234,
|
||||||
|
'id': 'A57B7771-6050-4CA8-A63C-443493EC98AB'
|
||||||
|
}
|
||||||
|
|
||||||
cls.release_listener(m_driver, loadbalancer, listener)
|
cls.release_listener(m_driver, loadbalancer, listener)
|
||||||
|
|
||||||
m_driver._release.assert_called_once_with(loadbalancer, listener,
|
m_driver._release.assert_called_once_with(loadbalancer, listener,
|
||||||
lbaas.delete_listener,
|
lbaas.delete_listener,
|
||||||
listener.id)
|
listener['id'])
|
||||||
|
|
||||||
def test_ensure_pool(self):
|
def test_ensure_pool(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
expected_resp = mock.sentinel.expected_resp
|
expected_resp = mock.sentinel.expected_resp
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
'project_id': 'TEST_PROJECT',
|
||||||
project_id='TEST_PROJECT')
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
listener = obj_lbaas.LBaaSListener(
|
}
|
||||||
id='A57B7771-6050-4CA8-A63C-443493EC98AB',
|
listener = {
|
||||||
name='TEST_LISTENER_NAME',
|
'id': 'A57B7771-6050-4CA8-A63C-443493EC98AB',
|
||||||
protocol='TCP')
|
'name': 'TEST_LISTENER_NAME',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
}
|
||||||
m_driver._ensure_provisioned.return_value = expected_resp
|
m_driver._ensure_provisioned.return_value = expected_resp
|
||||||
|
|
||||||
resp = cls.ensure_pool(m_driver, loadbalancer, listener)
|
resp = cls.ensure_pool(m_driver, loadbalancer, listener)
|
||||||
|
@ -255,10 +282,10 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
loadbalancer, mock.ANY, m_driver._create_pool,
|
loadbalancer, mock.ANY, m_driver._create_pool,
|
||||||
m_driver._find_pool)
|
m_driver._find_pool)
|
||||||
pool = m_driver._ensure_provisioned.call_args[0][1]
|
pool = m_driver._ensure_provisioned.call_args[0][1]
|
||||||
self.assertEqual(listener.name, pool.name)
|
self.assertEqual(listener['name'], pool['name'])
|
||||||
self.assertEqual(loadbalancer.project_id, pool.project_id)
|
self.assertEqual(loadbalancer['project_id'], pool['project_id'])
|
||||||
self.assertEqual(listener.id, pool.listener_id)
|
self.assertEqual(listener['id'], pool['listener_id'])
|
||||||
self.assertEqual(listener.protocol, pool.protocol)
|
self.assertEqual(listener['protocol'], pool['protocol'])
|
||||||
self.assertEqual(expected_resp, resp)
|
self.assertEqual(expected_resp, resp)
|
||||||
|
|
||||||
def test_release_pool(self):
|
def test_release_pool(self):
|
||||||
|
@ -266,23 +293,34 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = mock.Mock()
|
loadbalancer = mock.Mock()
|
||||||
pool = mock.Mock()
|
pool = {
|
||||||
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'listener_id': 'A57B7771-6050-4CA8-A63C-443493EC98AB',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'id': 'D4F35594-27EB-4F4C-930C-31DD40F53B77'
|
||||||
|
}
|
||||||
|
|
||||||
cls.release_pool(m_driver, loadbalancer, pool)
|
cls.release_pool(m_driver, loadbalancer, pool)
|
||||||
|
|
||||||
m_driver._release.assert_called_once_with(loadbalancer, pool,
|
m_driver._release.assert_called_once_with(loadbalancer, pool,
|
||||||
lbaas.delete_pool,
|
lbaas.delete_pool,
|
||||||
pool.id)
|
pool['id'])
|
||||||
|
|
||||||
def test_ensure_member(self):
|
def test_ensure_member(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
expected_resp = mock.sentinel.expected_resp
|
expected_resp = mock.sentinel.expected_resp
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
project_id='TEST_PROJECT')
|
'project_id': 'TEST_PROJECT'
|
||||||
pool = obj_lbaas.LBaaSPool(project_id='TEST_PROJECT',
|
}
|
||||||
id='D4F35594-27EB-4F4C-930C-31DD40F53B77')
|
pool = {
|
||||||
|
'id': 'D4F35594-27EB-4F4C-930C-31DD40F53B77',
|
||||||
|
'project_id': 'TEST_PROJECT'
|
||||||
|
}
|
||||||
|
|
||||||
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
|
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
|
||||||
ip = '1.2.3.4'
|
ip = '1.2.3.4'
|
||||||
port = 1234
|
port = 1234
|
||||||
|
@ -299,41 +337,63 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
loadbalancer, mock.ANY, m_driver._create_member,
|
loadbalancer, mock.ANY, m_driver._create_member,
|
||||||
m_driver._find_member)
|
m_driver._find_member)
|
||||||
member = m_driver._ensure_provisioned.call_args[0][1]
|
member = m_driver._ensure_provisioned.call_args[0][1]
|
||||||
self.assertEqual("%s/%s:%s" % (namespace, name, port), member.name)
|
self.assertEqual("%s/%s:%s" % (namespace, name, port), member['name'])
|
||||||
self.assertEqual(pool.project_id, member.project_id)
|
self.assertEqual(pool['project_id'], member['project_id'])
|
||||||
self.assertEqual(pool.id, member.pool_id)
|
self.assertEqual(pool['id'], member['pool_id'])
|
||||||
self.assertEqual(subnet_id, member.subnet_id)
|
self.assertEqual(subnet_id, member['subnet_id'])
|
||||||
self.assertEqual(ip, str(member.ip))
|
self.assertEqual(ip, str(member['ip']))
|
||||||
self.assertEqual(port, member.port)
|
self.assertEqual(port, member['port'])
|
||||||
self.assertEqual(expected_resp, resp)
|
self.assertEqual(expected_resp, resp)
|
||||||
|
|
||||||
def test_release_member(self):
|
def test_release_member(self):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = mock.Mock()
|
loadbalancer = {
|
||||||
member = mock.Mock()
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'security_groups': [],
|
||||||
|
'provider': None
|
||||||
|
}
|
||||||
|
|
||||||
|
member = {
|
||||||
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'pool_id': 'D4F35594-27EB-4F4C-930C-31DD40F53B77',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'port': 1234,
|
||||||
|
'id': '3A70CEC0-392D-4BC1-A27C-06E63A0FD54F'
|
||||||
|
}
|
||||||
|
|
||||||
cls.release_member(m_driver, loadbalancer, member)
|
cls.release_member(m_driver, loadbalancer, member)
|
||||||
|
|
||||||
m_driver._release.assert_called_once_with(loadbalancer, member,
|
m_driver._release.assert_called_once_with(loadbalancer, member,
|
||||||
lbaas.delete_member,
|
lbaas.delete_member,
|
||||||
member.id, member.pool_id)
|
member['id'],
|
||||||
|
member['pool_id'])
|
||||||
|
|
||||||
def test_create_loadbalancer(self):
|
def test_create_loadbalancer(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
'name': 'TEST_NAME',
|
||||||
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
'project_id': 'TEST_PROJECT',
|
||||||
security_groups=[])
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'security_groups': [],
|
||||||
|
'provider': None
|
||||||
|
}
|
||||||
|
|
||||||
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
||||||
req = {
|
req = {
|
||||||
'name': loadbalancer.name,
|
'name': loadbalancer['name'],
|
||||||
'project_id': loadbalancer.project_id,
|
'project_id': loadbalancer['project_id'],
|
||||||
'vip_address': str(loadbalancer.ip),
|
'vip_address': str(loadbalancer['ip']),
|
||||||
'vip_subnet_id': loadbalancer.subnet_id,
|
'vip_subnet_id': loadbalancer['subnet_id'],
|
||||||
}
|
}
|
||||||
resp = o_lb.LoadBalancer(id=loadbalancer_id, provider='haproxy')
|
resp = o_lb.LoadBalancer(id=loadbalancer_id, provider='haproxy')
|
||||||
lbaas.create_load_balancer.return_value = resp
|
lbaas.create_load_balancer.return_value = resp
|
||||||
|
@ -342,27 +402,28 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
|
|
||||||
ret = cls._create_loadbalancer(m_driver, loadbalancer)
|
ret = cls._create_loadbalancer(m_driver, loadbalancer)
|
||||||
lbaas.create_load_balancer.assert_called_once_with(**req)
|
lbaas.create_load_balancer.assert_called_once_with(**req)
|
||||||
for attr in loadbalancer.obj_fields:
|
self.assertEqual(loadbalancer, ret)
|
||||||
self.assertEqual(getattr(loadbalancer, attr),
|
self.assertEqual(loadbalancer_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(loadbalancer_id, ret.id)
|
|
||||||
|
|
||||||
def test_create_loadbalancer_provider_defined(self):
|
def test_create_loadbalancer_provider_defined(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
'name': 'TEST_NAME',
|
||||||
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
'project_id': 'TEST_PROJECT',
|
||||||
security_groups=[],
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
provider='amphora')
|
'ip': '1.2.3.4',
|
||||||
|
'security_groups': [],
|
||||||
|
'provider': 'amphora'
|
||||||
|
}
|
||||||
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
||||||
req = {
|
req = {
|
||||||
'name': loadbalancer.name,
|
'name': loadbalancer['name'],
|
||||||
'project_id': loadbalancer.project_id,
|
'project_id': loadbalancer['project_id'],
|
||||||
'vip_address': str(loadbalancer.ip),
|
'vip_address': str(loadbalancer['ip']),
|
||||||
'vip_subnet_id': loadbalancer.subnet_id,
|
'vip_subnet_id': loadbalancer['subnet_id'],
|
||||||
'provider': loadbalancer.provider,
|
'provider': loadbalancer['provider'],
|
||||||
}
|
}
|
||||||
resp = o_lb.LoadBalancer(id=loadbalancer_id, provider='amphora')
|
resp = o_lb.LoadBalancer(id=loadbalancer_id, provider='amphora')
|
||||||
lbaas.create_load_balancer.return_value = resp
|
lbaas.create_load_balancer.return_value = resp
|
||||||
|
@ -371,27 +432,28 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
|
|
||||||
ret = cls._create_loadbalancer(m_driver, loadbalancer)
|
ret = cls._create_loadbalancer(m_driver, loadbalancer)
|
||||||
lbaas.create_load_balancer.assert_called_once_with(**req)
|
lbaas.create_load_balancer.assert_called_once_with(**req)
|
||||||
for attr in loadbalancer.obj_fields:
|
self.assertEqual(loadbalancer, ret)
|
||||||
self.assertEqual(getattr(loadbalancer, attr),
|
self.assertEqual(loadbalancer_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(loadbalancer_id, ret.id)
|
|
||||||
|
|
||||||
def test_create_loadbalancer_provider_mismatch(self):
|
def test_create_loadbalancer_provider_mismatch(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
'name': 'TEST_NAME',
|
||||||
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
'project_id': 'TEST_PROJECT',
|
||||||
security_groups=[],
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
provider='amphora')
|
'ip': '1.2.3.4',
|
||||||
|
'security_groups': [],
|
||||||
|
'provider': 'amphora'
|
||||||
|
}
|
||||||
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
||||||
req = {
|
req = {
|
||||||
'name': loadbalancer.name,
|
'name': loadbalancer['name'],
|
||||||
'project_id': loadbalancer.project_id,
|
'project_id': loadbalancer['project_id'],
|
||||||
'vip_address': str(loadbalancer.ip),
|
'vip_address': str(loadbalancer['ip']),
|
||||||
'vip_subnet_id': loadbalancer.subnet_id,
|
'vip_subnet_id': loadbalancer['subnet_id'],
|
||||||
'provider': loadbalancer.provider,
|
'provider': loadbalancer['provider'],
|
||||||
}
|
}
|
||||||
resp = o_lb.LoadBalancer(id=loadbalancer_id, provider='haproxy')
|
resp = o_lb.LoadBalancer(id=loadbalancer_id, provider='haproxy')
|
||||||
lbaas.create_load_balancer.return_value = resp
|
lbaas.create_load_balancer.return_value = resp
|
||||||
|
@ -406,10 +468,14 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
'name': 'TEST_NAME',
|
||||||
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
'project_id': 'TEST_PROJECT',
|
||||||
provider='haproxy', security_groups=[])
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'security_groups': [],
|
||||||
|
'provider': 'haproxy'
|
||||||
|
}
|
||||||
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
||||||
resp = iter([o_lb.LoadBalancer(id=loadbalancer_id, provider='haproxy',
|
resp = iter([o_lb.LoadBalancer(id=loadbalancer_id, provider='haproxy',
|
||||||
provisioning_status='ACTIVE')])
|
provisioning_status='ACTIVE')])
|
||||||
|
@ -419,15 +485,13 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
|
|
||||||
ret = cls._find_loadbalancer(m_driver, loadbalancer)
|
ret = cls._find_loadbalancer(m_driver, loadbalancer)
|
||||||
lbaas.load_balancers.assert_called_once_with(
|
lbaas.load_balancers.assert_called_once_with(
|
||||||
name=loadbalancer.name,
|
name=loadbalancer['name'],
|
||||||
project_id=loadbalancer.project_id,
|
project_id=loadbalancer['project_id'],
|
||||||
vip_address=str(loadbalancer.ip),
|
vip_address=str(loadbalancer['ip']),
|
||||||
vip_subnet_id=loadbalancer.subnet_id,
|
vip_subnet_id=loadbalancer['subnet_id'],
|
||||||
provider='haproxy')
|
provider='haproxy')
|
||||||
for attr in loadbalancer.obj_fields:
|
self.assertEqual(loadbalancer, ret)
|
||||||
self.assertEqual(getattr(loadbalancer, attr),
|
self.assertEqual(loadbalancer_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(loadbalancer_id, ret.id)
|
|
||||||
m_driver.release_loadbalancer.assert_not_called()
|
m_driver.release_loadbalancer.assert_not_called()
|
||||||
|
|
||||||
def test_find_loadbalancer_not_found(self):
|
def test_find_loadbalancer_not_found(self):
|
||||||
|
@ -437,15 +501,22 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
||||||
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1')
|
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1')
|
||||||
|
loadbalancer = {
|
||||||
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'provider': None
|
||||||
|
}
|
||||||
resp = iter([])
|
resp = iter([])
|
||||||
lbaas.load_balancers.return_value = resp
|
lbaas.load_balancers.return_value = resp
|
||||||
|
|
||||||
ret = cls._find_loadbalancer(m_driver, loadbalancer)
|
ret = cls._find_loadbalancer(m_driver, loadbalancer)
|
||||||
lbaas.load_balancers.assert_called_once_with(
|
lbaas.load_balancers.assert_called_once_with(
|
||||||
name=loadbalancer.name,
|
name=loadbalancer['name'],
|
||||||
project_id=loadbalancer.project_id,
|
project_id=loadbalancer['project_id'],
|
||||||
vip_address=str(loadbalancer.ip),
|
vip_address=str(loadbalancer['ip']),
|
||||||
vip_subnet_id=loadbalancer.subnet_id,
|
vip_subnet_id=loadbalancer['subnet_id'],
|
||||||
provider=None)
|
provider=None)
|
||||||
self.assertIsNone(ret)
|
self.assertIsNone(ret)
|
||||||
m_driver.release_loadbalancer.assert_not_called()
|
m_driver.release_loadbalancer.assert_not_called()
|
||||||
|
@ -454,9 +525,13 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
'name': 'TEST_NAME',
|
||||||
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1')
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'provider': None
|
||||||
|
}
|
||||||
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
||||||
resp = iter([o_lb.LoadBalancer(id=loadbalancer_id, provider='haproxy',
|
resp = iter([o_lb.LoadBalancer(id=loadbalancer_id, provider='haproxy',
|
||||||
provisioning_status='ERROR')])
|
provisioning_status='ERROR')])
|
||||||
|
@ -466,10 +541,10 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
|
|
||||||
ret = cls._find_loadbalancer(m_driver, loadbalancer)
|
ret = cls._find_loadbalancer(m_driver, loadbalancer)
|
||||||
lbaas.load_balancers.assert_called_once_with(
|
lbaas.load_balancers.assert_called_once_with(
|
||||||
name=loadbalancer.name,
|
name=loadbalancer['name'],
|
||||||
project_id=loadbalancer.project_id,
|
project_id=loadbalancer['project_id'],
|
||||||
vip_address=str(loadbalancer.ip),
|
vip_address=str(loadbalancer['ip']),
|
||||||
vip_subnet_id=loadbalancer.subnet_id,
|
vip_subnet_id=loadbalancer['subnet_id'],
|
||||||
provider=None)
|
provider=None)
|
||||||
self.assertIsNone(ret)
|
self.assertIsNone(ret)
|
||||||
m_driver.release_loadbalancer.assert_called_once()
|
m_driver.release_loadbalancer.assert_called_once()
|
||||||
|
@ -478,69 +553,80 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
listener = obj_lbaas.LBaaSListener(
|
listener = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
|
'name': 'TEST_NAME',
|
||||||
port=1234, loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 1234
|
||||||
|
}
|
||||||
listener_id = 'A57B7771-6050-4CA8-A63C-443493EC98AB'
|
listener_id = 'A57B7771-6050-4CA8-A63C-443493EC98AB'
|
||||||
|
|
||||||
req = {
|
req = {
|
||||||
'name': listener.name,
|
'name': listener['name'],
|
||||||
'project_id': listener.project_id,
|
'project_id': listener['project_id'],
|
||||||
'loadbalancer_id': listener.loadbalancer_id,
|
'loadbalancer_id': listener['loadbalancer_id'],
|
||||||
'protocol': listener.protocol,
|
'protocol': listener['protocol'],
|
||||||
'protocol_port': listener.port}
|
'protocol_port': listener['port']}
|
||||||
resp = o_lis.Listener(id=listener_id)
|
resp = o_lis.Listener(id=listener_id)
|
||||||
lbaas.create_listener.return_value = resp
|
lbaas.create_listener.return_value = resp
|
||||||
|
|
||||||
ret = cls._create_listener(m_driver, listener)
|
ret = cls._create_listener(m_driver, listener)
|
||||||
lbaas.create_listener.assert_called_once_with(**req)
|
lbaas.create_listener.assert_called_once_with(**req)
|
||||||
for attr in listener.obj_fields:
|
self.assertEqual(listener, ret)
|
||||||
self.assertEqual(getattr(listener, attr),
|
self.assertEqual(listener_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(listener_id, ret.id)
|
|
||||||
|
|
||||||
def test_find_listener(self):
|
def test_find_listener(self):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
listener = obj_lbaas.LBaaSListener(
|
}
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
|
listener = {
|
||||||
port=1234, loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 1234
|
||||||
|
}
|
||||||
listener_id = 'A57B7771-6050-4CA8-A63C-443493EC98AB'
|
listener_id = 'A57B7771-6050-4CA8-A63C-443493EC98AB'
|
||||||
lbaas.listeners.return_value = iter([o_lis.Listener(id=listener_id)])
|
lbaas.listeners.return_value = iter([o_lis.Listener(id=listener_id)])
|
||||||
|
|
||||||
ret = cls._find_listener(m_driver, listener, loadbalancer)
|
ret = cls._find_listener(m_driver, listener, loadbalancer)
|
||||||
lbaas.listeners.assert_called_once_with(
|
lbaas.listeners.assert_called_once_with(
|
||||||
name=listener.name,
|
name=listener['name'],
|
||||||
project_id=listener.project_id,
|
project_id=listener['project_id'],
|
||||||
load_balancer_id=listener.loadbalancer_id,
|
load_balancer_id=listener['loadbalancer_id'],
|
||||||
protocol=listener.protocol,
|
protocol=listener['protocol'],
|
||||||
protocol_port=listener.port)
|
protocol_port=listener['port'])
|
||||||
for attr in listener.obj_fields:
|
self.assertEqual(listener, ret)
|
||||||
self.assertEqual(getattr(listener, attr),
|
self.assertEqual(listener_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(listener_id, ret.id)
|
|
||||||
|
|
||||||
def test_find_listener_not_found(self):
|
def test_find_listener_not_found(self):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
listener = obj_lbaas.LBaaSListener(
|
}
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
|
listener = {
|
||||||
port=1234, loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 1234
|
||||||
|
}
|
||||||
resp = iter([])
|
resp = iter([])
|
||||||
lbaas.listeners.return_value = resp
|
lbaas.listeners.return_value = resp
|
||||||
|
|
||||||
ret = cls._find_listener(m_driver, listener, loadbalancer)
|
ret = cls._find_listener(m_driver, listener, loadbalancer)
|
||||||
lbaas.listeners.assert_called_once_with(
|
lbaas.listeners.assert_called_once_with(
|
||||||
name=listener.name,
|
name=listener['name'],
|
||||||
project_id=listener.project_id,
|
project_id=listener['project_id'],
|
||||||
load_balancer_id=listener.loadbalancer_id,
|
load_balancer_id=listener['loadbalancer_id'],
|
||||||
protocol=listener.protocol,
|
protocol=listener['protocol'],
|
||||||
protocol_port=listener.port)
|
protocol_port=listener['port'])
|
||||||
self.assertIsNone(ret)
|
self.assertIsNone(ret)
|
||||||
|
|
||||||
def test_create_pool(self):
|
def test_create_pool(self):
|
||||||
|
@ -548,44 +634,49 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
lb_algorithm = 'ROUND_ROBIN'
|
lb_algorithm = 'ROUND_ROBIN'
|
||||||
pool = obj_lbaas.LBaaSPool(
|
pool = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
|
'name': 'TEST_NAME',
|
||||||
listener_id='A57B7771-6050-4CA8-A63C-443493EC98AB',
|
'project_id': 'TEST_PROJECT',
|
||||||
loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'listener_id': 'A57B7771-6050-4CA8-A63C-443493EC98AB',
|
||||||
|
'protocol': 'TCP'
|
||||||
|
}
|
||||||
pool_id = 'D4F35594-27EB-4F4C-930C-31DD40F53B77'
|
pool_id = 'D4F35594-27EB-4F4C-930C-31DD40F53B77'
|
||||||
|
|
||||||
req = {
|
req = {
|
||||||
'name': pool.name,
|
'name': pool['name'],
|
||||||
'project_id': pool.project_id,
|
'project_id': pool['project_id'],
|
||||||
'listener_id': pool.listener_id,
|
'listener_id': pool['listener_id'],
|
||||||
'loadbalancer_id': pool.loadbalancer_id,
|
'loadbalancer_id': pool['loadbalancer_id'],
|
||||||
'protocol': pool.protocol,
|
'protocol': pool['protocol'],
|
||||||
'lb_algorithm': lb_algorithm}
|
'lb_algorithm': lb_algorithm}
|
||||||
resp = o_pool.Pool(id=pool_id)
|
resp = o_pool.Pool(id=pool_id)
|
||||||
lbaas.create_pool.return_value = resp
|
lbaas.create_pool.return_value = resp
|
||||||
|
|
||||||
ret = cls._create_pool(m_driver, pool)
|
ret = cls._create_pool(m_driver, pool)
|
||||||
lbaas.create_pool.assert_called_once_with(**req)
|
lbaas.create_pool.assert_called_once_with(**req)
|
||||||
for attr in pool.obj_fields:
|
self.assertEqual(pool, ret)
|
||||||
self.assertEqual(getattr(pool, attr),
|
self.assertEqual(pool_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(pool_id, ret.id)
|
|
||||||
|
|
||||||
def test_create_pool_with_different_lb_algorithm(self):
|
def test_create_pool_with_different_lb_algorithm(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
lb_algorithm = 'SOURCE_IP_PORT'
|
lb_algorithm = 'SOURCE_IP_PORT'
|
||||||
pool = obj_lbaas.LBaaSPool(
|
pool = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
|
'name': 'TEST_NAME',
|
||||||
listener_id='A57B7771-6050-4CA8-A63C-443493EC98AB',
|
'project_id': 'TEST_PROJECT',
|
||||||
loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'listener_id': 'A57B7771-6050-4CA8-A63C-443493EC98AB',
|
||||||
|
'protocol': 'TCP'
|
||||||
|
}
|
||||||
pool_id = 'D4F35594-27EB-4F4C-930C-31DD40F53B77'
|
pool_id = 'D4F35594-27EB-4F4C-930C-31DD40F53B77'
|
||||||
req = {
|
req = {
|
||||||
'name': pool.name,
|
'name': pool['name'],
|
||||||
'project_id': pool.project_id,
|
'project_id': pool['project_id'],
|
||||||
'listener_id': pool.listener_id,
|
'listener_id': pool['listener_id'],
|
||||||
'loadbalancer_id': pool.loadbalancer_id,
|
'loadbalancer_id': pool['loadbalancer_id'],
|
||||||
'protocol': pool.protocol,
|
'protocol': pool['protocol'],
|
||||||
'lb_algorithm': lb_algorithm}
|
'lb_algorithm': lb_algorithm}
|
||||||
resp = o_pool.Pool(id=pool_id)
|
resp = o_pool.Pool(id=pool_id)
|
||||||
lbaas.create_pool.return_value = resp
|
lbaas.create_pool.return_value = resp
|
||||||
|
@ -596,26 +687,27 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
|
|
||||||
ret = cls._create_pool(m_driver, pool)
|
ret = cls._create_pool(m_driver, pool)
|
||||||
lbaas.create_pool.assert_called_once_with(**req)
|
lbaas.create_pool.assert_called_once_with(**req)
|
||||||
for attr in pool.obj_fields:
|
self.assertEqual(pool, ret)
|
||||||
self.assertEqual(getattr(pool, attr),
|
self.assertEqual(pool_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(pool_id, ret.id)
|
|
||||||
|
|
||||||
def test_create_pool_conflict(self):
|
def test_create_pool_conflict(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
lb_algorithm = 'ROUND_ROBIN'
|
lb_algorithm = 'ROUND_ROBIN'
|
||||||
pool = obj_lbaas.LBaaSPool(
|
pool = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
|
'name': 'TEST_NAME',
|
||||||
listener_id='A57B7771-6050-4CA8-A63C-443493EC98AB',
|
'project_id': 'TEST_PROJECT',
|
||||||
loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'listener_id': 'A57B7771-6050-4CA8-A63C-443493EC98AB',
|
||||||
|
'protocol': 'TCP'
|
||||||
|
}
|
||||||
req = {
|
req = {
|
||||||
'name': pool.name,
|
'name': pool['name'],
|
||||||
'project_id': pool.project_id,
|
'project_id': pool['project_id'],
|
||||||
'listener_id': pool.listener_id,
|
'listener_id': pool['listener_id'],
|
||||||
'loadbalancer_id': pool.loadbalancer_id,
|
'loadbalancer_id': pool['loadbalancer_id'],
|
||||||
'protocol': pool.protocol,
|
'protocol': pool['protocol'],
|
||||||
'lb_algorithm': lb_algorithm}
|
'lb_algorithm': lb_algorithm}
|
||||||
lbaas.create_pool.side_effect = os_exc.BadRequestException
|
lbaas.create_pool.side_effect = os_exc.BadRequestException
|
||||||
|
|
||||||
|
@ -627,120 +719,134 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
pool = obj_lbaas.LBaaSPool(
|
}
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
|
pool = {
|
||||||
listener_id='A57B7771-6050-4CA8-A63C-443493EC98AB',
|
'name': 'TEST_NAME',
|
||||||
loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'listener_id': 'A57B7771-6050-4CA8-A63C-443493EC98AB',
|
||||||
|
'protocol': 'TCP'
|
||||||
|
}
|
||||||
pool_id = 'D4F35594-27EB-4F4C-930C-31DD40F53B77'
|
pool_id = 'D4F35594-27EB-4F4C-930C-31DD40F53B77'
|
||||||
resp = [o_pool.Pool(id=pool_id,
|
resp = [o_pool.Pool(id=pool_id,
|
||||||
listeners=[{"id": pool.listener_id}])]
|
listeners=[{"id": pool['listener_id']}])]
|
||||||
lbaas.pools.return_value = resp
|
lbaas.pools.return_value = resp
|
||||||
|
|
||||||
ret = cls._find_pool(m_driver, pool, loadbalancer)
|
ret = cls._find_pool(m_driver, pool, loadbalancer)
|
||||||
lbaas.pools.assert_called_once_with(
|
lbaas.pools.assert_called_once_with(
|
||||||
name=pool.name,
|
name=pool['name'],
|
||||||
project_id=pool.project_id,
|
project_id=pool['project_id'],
|
||||||
loadbalancer_id=pool.loadbalancer_id,
|
loadbalancer_id=pool['loadbalancer_id'],
|
||||||
protocol=pool.protocol)
|
protocol=pool['protocol'])
|
||||||
for attr in pool.obj_fields:
|
self.assertEqual(pool, ret)
|
||||||
self.assertEqual(getattr(pool, attr),
|
self.assertEqual(pool_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(pool_id, ret.id)
|
|
||||||
|
|
||||||
def test_find_pool_by_listener_not_found(self):
|
def test_find_pool_by_listener_not_found(self):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
|
loadbalancer = {
|
||||||
id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
||||||
pool = obj_lbaas.LBaaSPool(
|
}
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
|
pool = {
|
||||||
listener_id='A57B7771-6050-4CA8-A63C-443493EC98AB',
|
'name': 'TEST_NAME',
|
||||||
loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'loadbalancer_id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
|
||||||
|
'listener_id': 'A57B7771-6050-4CA8-A63C-443493EC98AB',
|
||||||
|
'protocol': 'TCP'
|
||||||
|
}
|
||||||
resp = []
|
resp = []
|
||||||
lbaas.pools.return_value = resp
|
lbaas.pools.return_value = resp
|
||||||
|
|
||||||
ret = cls._find_pool(m_driver, pool, loadbalancer)
|
ret = cls._find_pool(m_driver, pool, loadbalancer)
|
||||||
lbaas.pools.assert_called_once_with(
|
lbaas.pools.assert_called_once_with(
|
||||||
name=pool.name,
|
name=pool['name'],
|
||||||
project_id=pool.project_id,
|
project_id=pool['project_id'],
|
||||||
loadbalancer_id=pool.loadbalancer_id,
|
loadbalancer_id=pool['loadbalancer_id'],
|
||||||
protocol=pool.protocol)
|
protocol=pool['protocol'])
|
||||||
self.assertIsNone(ret)
|
self.assertIsNone(ret)
|
||||||
|
|
||||||
def test_create_member(self):
|
def test_create_member(self):
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
member = obj_lbaas.LBaaSMember(
|
member = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
'name': 'TEST_NAME',
|
||||||
port=1234, subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
'project_id': 'TEST_PROJECT',
|
||||||
pool_id='D4F35594-27EB-4F4C-930C-31DD40F53B77')
|
'pool_id': 'D4F35594-27EB-4F4C-930C-31DD40F53B77',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'port': 1234
|
||||||
|
}
|
||||||
member_id = '3A70CEC0-392D-4BC1-A27C-06E63A0FD54F'
|
member_id = '3A70CEC0-392D-4BC1-A27C-06E63A0FD54F'
|
||||||
req = {
|
req = {
|
||||||
'name': member.name,
|
'name': member['name'],
|
||||||
'project_id': member.project_id,
|
'project_id': member['project_id'],
|
||||||
'subnet_id': member.subnet_id,
|
'subnet_id': member['subnet_id'],
|
||||||
'address': str(member.ip),
|
'address': str(member['ip']),
|
||||||
'protocol_port': member.port}
|
'protocol_port': member['port']}
|
||||||
resp = o_mem.Member(id=member_id)
|
resp = o_mem.Member(id=member_id)
|
||||||
lbaas.create_member.return_value = resp
|
lbaas.create_member.return_value = resp
|
||||||
|
|
||||||
ret = cls._create_member(m_driver, member)
|
ret = cls._create_member(m_driver, member)
|
||||||
lbaas.create_member.assert_called_once_with(member.pool_id, **req)
|
lbaas.create_member.assert_called_once_with(member['pool_id'], **req)
|
||||||
for attr in member.obj_fields:
|
self.assertEqual(member, ret)
|
||||||
self.assertEqual(getattr(member, attr),
|
self.assertEqual(member_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(member_id, ret.id)
|
|
||||||
|
|
||||||
def test_find_member(self):
|
def test_find_member(self):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer()
|
loadbalancer = obj_lbaas.LBaaSLoadBalancer()
|
||||||
member = obj_lbaas.LBaaSMember(
|
member = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
'name': 'TEST_NAME',
|
||||||
port=1234, subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
'project_id': 'TEST_PROJECT',
|
||||||
pool_id='D4F35594-27EB-4F4C-930C-31DD40F53B77')
|
'pool_id': 'D4F35594-27EB-4F4C-930C-31DD40F53B77',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'port': 1234
|
||||||
|
}
|
||||||
member_id = '3A70CEC0-392D-4BC1-A27C-06E63A0FD54F'
|
member_id = '3A70CEC0-392D-4BC1-A27C-06E63A0FD54F'
|
||||||
resp = iter([o_mem.Member(id=member_id)])
|
resp = iter([o_mem.Member(id=member_id)])
|
||||||
lbaas.members.return_value = resp
|
lbaas.members.return_value = resp
|
||||||
|
|
||||||
ret = cls._find_member(m_driver, member, loadbalancer)
|
ret = cls._find_member(m_driver, member, loadbalancer)
|
||||||
lbaas.members.assert_called_once_with(
|
lbaas.members.assert_called_once_with(
|
||||||
member.pool_id,
|
member['pool_id'],
|
||||||
name=member.name,
|
name=member['name'],
|
||||||
project_id=member.project_id,
|
project_id=member['project_id'],
|
||||||
subnet_id=member.subnet_id,
|
subnet_id=member['subnet_id'],
|
||||||
address=member.ip,
|
address=member['ip'],
|
||||||
protocol_port=member.port)
|
protocol_port=member['port'])
|
||||||
for attr in member.obj_fields:
|
self.assertEqual(member, ret)
|
||||||
self.assertEqual(getattr(member, attr),
|
self.assertEqual(member_id, ret['id'])
|
||||||
getattr(ret, attr))
|
|
||||||
self.assertEqual(member_id, ret.id)
|
|
||||||
|
|
||||||
def test_find_member_not_found(self):
|
def test_find_member_not_found(self):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = obj_lbaas.LBaaSLoadBalancer()
|
loadbalancer = obj_lbaas.LBaaSLoadBalancer()
|
||||||
member = obj_lbaas.LBaaSMember(
|
member = {
|
||||||
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
|
'name': 'TEST_NAME',
|
||||||
port=1234, subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
'project_id': 'TEST_PROJECT',
|
||||||
pool_id='D4F35594-27EB-4F4C-930C-31DD40F53B77')
|
'pool_id': 'D4F35594-27EB-4F4C-930C-31DD40F53B77',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'port': 1234
|
||||||
|
}
|
||||||
resp = iter([])
|
resp = iter([])
|
||||||
lbaas.members.return_value = resp
|
lbaas.members.return_value = resp
|
||||||
|
|
||||||
ret = cls._find_member(m_driver, member, loadbalancer)
|
ret = cls._find_member(m_driver, member, loadbalancer)
|
||||||
lbaas.members.assert_called_once_with(
|
lbaas.members.assert_called_once_with(
|
||||||
member.pool_id,
|
member['pool_id'],
|
||||||
name=member.name,
|
name=member['name'],
|
||||||
project_id=member.project_id,
|
project_id=member['project_id'],
|
||||||
subnet_id=member.subnet_id,
|
subnet_id=member['subnet_id'],
|
||||||
address=member.ip,
|
address=member['ip'],
|
||||||
protocol_port=member.port)
|
protocol_port=member['port'])
|
||||||
self.assertIsNone(ret)
|
self.assertIsNone(ret)
|
||||||
|
|
||||||
def test_ensure(self):
|
def test_ensure(self):
|
||||||
|
@ -888,7 +994,14 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = mock.Mock()
|
loadbalancer = {
|
||||||
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'provider': None,
|
||||||
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
||||||
|
}
|
||||||
timeout = mock.sentinel.timeout
|
timeout = mock.sentinel.timeout
|
||||||
timer = [mock.sentinel.t0, mock.sentinel.t1]
|
timer = [mock.sentinel.t0, mock.sentinel.t1]
|
||||||
m_driver._provisioning_timer.return_value = timer
|
m_driver._provisioning_timer.return_value = timer
|
||||||
|
@ -897,13 +1010,20 @@ class TestLBaaSv2Driver(test_base.TestCase):
|
||||||
|
|
||||||
cls._wait_for_provisioning(m_driver, loadbalancer, timeout)
|
cls._wait_for_provisioning(m_driver, loadbalancer, timeout)
|
||||||
|
|
||||||
lbaas.get_load_balancer.assert_called_once_with(loadbalancer.id)
|
lbaas.get_load_balancer.assert_called_once_with(loadbalancer['id'])
|
||||||
|
|
||||||
def test_wait_for_provisioning_not_ready(self):
|
def test_wait_for_provisioning_not_ready(self):
|
||||||
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
lbaas = self.useFixture(k_fix.MockLBaaSClient()).client
|
||||||
cls = d_lbaasv2.LBaaSv2Driver
|
cls = d_lbaasv2.LBaaSv2Driver
|
||||||
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
|
||||||
loadbalancer = mock.Mock()
|
loadbalancer = {
|
||||||
|
'name': 'TEST_NAME',
|
||||||
|
'project_id': 'TEST_PROJECT',
|
||||||
|
'subnet_id': 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
|
||||||
|
'ip': '1.2.3.4',
|
||||||
|
'provider': None,
|
||||||
|
'id': '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
|
||||||
|
}
|
||||||
timeout = mock.sentinel.timeout
|
timeout = mock.sentinel.timeout
|
||||||
timer = [mock.sentinel.t0, mock.sentinel.t1]
|
timer = [mock.sentinel.t0, mock.sentinel.t1]
|
||||||
m_driver._provisioning_timer.return_value = timer
|
m_driver._provisioning_timer.return_value = timer
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,525 @@
|
||||||
|
# Copyright (c) 2016 Mirantis, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import os_vif.objects.network as osv_network
|
||||||
|
import os_vif.objects.subnet as osv_subnet
|
||||||
|
|
||||||
|
from kuryr_kubernetes import constants as k_const
|
||||||
|
from kuryr_kubernetes.controller.drivers import base as drv_base
|
||||||
|
from kuryr_kubernetes.controller.handlers import loadbalancer as h_lb
|
||||||
|
from kuryr_kubernetes.tests import base as test_base
|
||||||
|
from kuryr_kubernetes.tests.unit import kuryr_fixtures as k_fix
|
||||||
|
|
||||||
|
_SUPPORTED_LISTENER_PROT = ('HTTP', 'HTTPS', 'TCP')
|
||||||
|
|
||||||
|
|
||||||
|
def get_lb_crd():
|
||||||
|
return {
|
||||||
|
"metadata": {
|
||||||
|
"creationTimestamp": "2020-07-28T13:13:30Z",
|
||||||
|
"finalizers": [
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"generation": 6,
|
||||||
|
"name": "test",
|
||||||
|
"namespace": "default",
|
||||||
|
"resourceVersion": "111871",
|
||||||
|
"selfLink": "test",
|
||||||
|
"uid": "584fe3ea-04dd-43f7-be2f-713e861694ec"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"ip": "1.2.3.4",
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"port": 1,
|
||||||
|
"protocol": "TCP",
|
||||||
|
"targetPort": "1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"project_id": "1023456789120",
|
||||||
|
"security_groups_ids": [
|
||||||
|
"1d134e68-5653-4192-bda2-4214319af799",
|
||||||
|
"31d7b8c2-75f1-4125-9565-8c15c5cf046c"
|
||||||
|
],
|
||||||
|
"subnet_id": "123456789120",
|
||||||
|
"subsets": [
|
||||||
|
{
|
||||||
|
"addresses": [
|
||||||
|
{
|
||||||
|
"ip": "1.1.1.1",
|
||||||
|
"nodeName": "sarka-devstack",
|
||||||
|
"targetRef": {
|
||||||
|
"kind": "Pod",
|
||||||
|
"name": "test-f87976f9c-thjbk",
|
||||||
|
"namespace": "default",
|
||||||
|
"resourceVersion": "111701",
|
||||||
|
"uid": "10234567800"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"port": 2,
|
||||||
|
"protocol": "TCP"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "LoadBalancer"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"listeners": [
|
||||||
|
{
|
||||||
|
"id": "012345678912",
|
||||||
|
"loadbalancer_id": "01234567890",
|
||||||
|
"name": "default/test:TCP:80",
|
||||||
|
"port": 1,
|
||||||
|
"project_id": "12345678912",
|
||||||
|
"protocol": "TCP"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"loadbalancer": {
|
||||||
|
"id": "01234567890",
|
||||||
|
"ip": "1.2.3.4",
|
||||||
|
"name": "default/test",
|
||||||
|
"port_id": "1023456789120",
|
||||||
|
"project_id": "12345678912",
|
||||||
|
"provider": "amphora",
|
||||||
|
"security_groups": [
|
||||||
|
"1d134e68-5653-4192-bda2-4214319af799",
|
||||||
|
"31d7b8c2-75f1-4125-9565-8c15c5cf046c"
|
||||||
|
],
|
||||||
|
"subnet_id": "123456789120"
|
||||||
|
},
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"id": "0123456789",
|
||||||
|
"ip": "1.1.1.1",
|
||||||
|
"name": "default/test-f87976f9c-thjbk:8080",
|
||||||
|
"pool_id": "1234567890",
|
||||||
|
"port": 2,
|
||||||
|
"project_id": "12345678912",
|
||||||
|
"subnet_id": "123456789120"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pools": [
|
||||||
|
{
|
||||||
|
"id": "1234567890",
|
||||||
|
"listener_id": "012345678912",
|
||||||
|
"loadbalancer_id": "01234567890",
|
||||||
|
"name": "default/test:TCP:80",
|
||||||
|
"project_id": "12345678912",
|
||||||
|
"protocol": "TCP"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'service_pub_ip_info': {
|
||||||
|
'ip_id': '1.2.3.5',
|
||||||
|
'ip_addr': 'ec29d641-fec4-4f67-928a-124a76b3a888',
|
||||||
|
'alloc_method': 'kk'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FakeLBaaSDriver(drv_base.LBaaSDriver):
|
||||||
|
|
||||||
|
def ensure_loadbalancer(self, name, project_id, subnet_id, ip,
|
||||||
|
security_groups_ids, service_type, provider=None):
|
||||||
|
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'project_id': project_id,
|
||||||
|
'subnet_id': subnet_id,
|
||||||
|
'ip': ip,
|
||||||
|
'id': str(uuid.uuid4()),
|
||||||
|
'provider': provider
|
||||||
|
}
|
||||||
|
|
||||||
|
def ensure_listener(self, loadbalancer, protocol, port,
|
||||||
|
service_type='ClusterIP'):
|
||||||
|
if protocol not in _SUPPORTED_LISTENER_PROT:
|
||||||
|
return None
|
||||||
|
|
||||||
|
name = "%s:%s:%s" % (loadbalancer['name'], protocol, port)
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'project_id': loadbalancer['project_id'],
|
||||||
|
'loadbalancer_id': loadbalancer['id'],
|
||||||
|
'protocol': protocol,
|
||||||
|
'port': port,
|
||||||
|
'id': str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
|
||||||
|
def ensure_pool(self, loadbalancer, listener):
|
||||||
|
return {
|
||||||
|
'name': listener['name'],
|
||||||
|
'project_id': loadbalancer['project_id'],
|
||||||
|
'loadbalancer_id': loadbalancer['id'],
|
||||||
|
'listener_id': listener['id'],
|
||||||
|
'protocol': listener['protocol'],
|
||||||
|
'id': str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
|
||||||
|
def ensure_member(self, loadbalancer, pool, subnet_id, ip, port,
|
||||||
|
target_ref_namespace, target_ref_name, listener_port=None
|
||||||
|
):
|
||||||
|
name = "%s:%s:%s" % (loadbalancer['name'], ip, port)
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'project_id': pool['project_id'],
|
||||||
|
'pool_id': pool['id'],
|
||||||
|
'subnet_id': subnet_id,
|
||||||
|
'ip': ip,
|
||||||
|
'port': port,
|
||||||
|
'id': str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestKuryrLoadBalancerHandler(test_base.TestCase):
|
||||||
|
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base.'
|
||||||
|
'ServiceProjectDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base.'
|
||||||
|
'ServiceSecurityGroupsDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.config.CONF')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.ServicePubIpDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodSubnetsDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodProjectDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.LBaaSDriver.get_instance')
|
||||||
|
def test_init(self, m_get_drv_lbaas, m_get_drv_project,
|
||||||
|
m_get_drv_subnets, m_get_drv_service_pub_ip, m_cfg,
|
||||||
|
m_get_svc_sg_drv, m_get_svc_drv_project):
|
||||||
|
m_get_drv_lbaas.return_value = mock.sentinel.drv_lbaas
|
||||||
|
m_get_drv_project.return_value = mock.sentinel.drv_project
|
||||||
|
m_get_drv_subnets.return_value = mock.sentinel.drv_subnets
|
||||||
|
m_get_drv_service_pub_ip.return_value = mock.sentinel.drv_lb_ip
|
||||||
|
m_get_svc_drv_project.return_value = mock.sentinel.drv_svc_project
|
||||||
|
m_get_svc_sg_drv.return_value = mock.sentinel.drv_sg
|
||||||
|
m_cfg.kubernetes.endpoints_driver_octavia_provider = 'default'
|
||||||
|
handler = h_lb.KuryrLoadBalancerHandler()
|
||||||
|
|
||||||
|
self.assertEqual(mock.sentinel.drv_lbaas, handler._drv_lbaas)
|
||||||
|
self.assertEqual(mock.sentinel.drv_project, handler._drv_pod_project)
|
||||||
|
self.assertEqual(mock.sentinel.drv_subnets, handler._drv_pod_subnets)
|
||||||
|
self.assertEqual(mock.sentinel.drv_lb_ip, handler._drv_service_pub_ip)
|
||||||
|
self.assertIsNone(handler._lb_provider)
|
||||||
|
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base.'
|
||||||
|
'ServiceProjectDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base.'
|
||||||
|
'ServiceSecurityGroupsDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.config.CONF')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.ServicePubIpDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodSubnetsDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodProjectDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.LBaaSDriver.get_instance')
|
||||||
|
def test_init_provider_ovn(self, m_get_drv_lbaas, m_get_drv_project,
|
||||||
|
m_get_drv_subnets, m_get_drv_service_pub_ip,
|
||||||
|
m_cfg,
|
||||||
|
m_get_svc_sg_drv, m_get_svc_drv_project):
|
||||||
|
m_get_drv_lbaas.return_value = mock.sentinel.drv_lbaas
|
||||||
|
m_get_drv_project.return_value = mock.sentinel.drv_project
|
||||||
|
m_get_drv_subnets.return_value = mock.sentinel.drv_subnets
|
||||||
|
m_get_drv_service_pub_ip.return_value = mock.sentinel.drv_lb_ip
|
||||||
|
m_get_svc_drv_project.return_value = mock.sentinel.drv_svc_project
|
||||||
|
m_get_svc_sg_drv.return_value = mock.sentinel.drv_sg
|
||||||
|
m_cfg.kubernetes.endpoints_driver_octavia_provider = 'ovn'
|
||||||
|
handler = h_lb .KuryrLoadBalancerHandler()
|
||||||
|
|
||||||
|
self.assertEqual(mock.sentinel.drv_lbaas, handler._drv_lbaas)
|
||||||
|
self.assertEqual(mock.sentinel.drv_project, handler._drv_pod_project)
|
||||||
|
self.assertEqual(mock.sentinel.drv_subnets, handler._drv_pod_subnets)
|
||||||
|
self.assertEqual(mock.sentinel.drv_lb_ip, handler._drv_service_pub_ip)
|
||||||
|
self.assertEqual('ovn', handler._lb_provider)
|
||||||
|
|
||||||
|
def test_on_present(self):
|
||||||
|
m_drv_service_pub_ip = mock.Mock()
|
||||||
|
m_drv_service_pub_ip.acquire_service_pub_ip_info.return_value = None
|
||||||
|
m_drv_service_pub_ip.associate_pub_ip.return_value = True
|
||||||
|
|
||||||
|
m_handler = mock.Mock(spec=h_lb.KuryrLoadBalancerHandler)
|
||||||
|
m_handler._should_ignore.return_value = False
|
||||||
|
m_handler._sync_lbaas_members.return_value = True
|
||||||
|
m_handler._drv_service_pub_ip = m_drv_service_pub_ip
|
||||||
|
|
||||||
|
h_lb.KuryrLoadBalancerHandler.on_present(m_handler, get_lb_crd())
|
||||||
|
|
||||||
|
m_handler._should_ignore.assert_called_once_with(get_lb_crd())
|
||||||
|
m_handler._sync_lbaas_members.assert_called_once_with(
|
||||||
|
get_lb_crd())
|
||||||
|
|
||||||
|
def _fake_sync_lbaas_members(self, crd):
|
||||||
|
loadbalancer = {
|
||||||
|
"id": "01234567890",
|
||||||
|
"ip": "1.2.3.4",
|
||||||
|
"name": "default/test",
|
||||||
|
"port_id": "1023456789120",
|
||||||
|
"project_id": "12345678912",
|
||||||
|
"provider": "amphora",
|
||||||
|
"security_groups": [
|
||||||
|
"1d134e68-5653-4192-bda2-4214319af799",
|
||||||
|
"31d7b8c2-75f1-4125-9565-8c15c5cf046c"
|
||||||
|
],
|
||||||
|
"subnet_id": "123456789120"
|
||||||
|
}
|
||||||
|
loadbalancer['port_id'] = 12345678
|
||||||
|
crd['status']['loadbalancer'] = loadbalancer
|
||||||
|
crd['status']['service_pub_ip_info'] = None
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_on_present_loadbalancer_service(self):
|
||||||
|
floating_ip = {'floating_ip_address': '1.2.3.5',
|
||||||
|
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'}
|
||||||
|
|
||||||
|
service_pub_ip_info = {
|
||||||
|
'ip_id': floating_ip['id'],
|
||||||
|
'ip_addr': floating_ip['floating_ip_address'],
|
||||||
|
'alloc_method': 'kk'
|
||||||
|
}
|
||||||
|
crd = get_lb_crd()
|
||||||
|
m_drv_service_pub_ip = mock.Mock()
|
||||||
|
m_drv_service_pub_ip.acquire_service_pub_ip_info.return_value = (
|
||||||
|
service_pub_ip_info)
|
||||||
|
m_drv_service_pub_ip.associate_pub_ip.return_value = True
|
||||||
|
|
||||||
|
h = mock.Mock(spec=h_lb.KuryrLoadBalancerHandler)
|
||||||
|
h._should_ignore.return_value = False
|
||||||
|
h._sync_lbaas_members.return_value = self._fake_sync_lbaas_members(crd)
|
||||||
|
h._drv_service_pub_ip = m_drv_service_pub_ip
|
||||||
|
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
|
||||||
|
kubernetes.get_kubernetes_client = mock.Mock()
|
||||||
|
kubernetes.get_kubernetes_client()
|
||||||
|
h_lb.KuryrLoadBalancerHandler.on_present(h, crd)
|
||||||
|
h._should_ignore.assert_called_once_with(crd)
|
||||||
|
h._update_lb_status.assert_called()
|
||||||
|
|
||||||
|
@mock.patch('kuryr_kubernetes.utils.get_lbaas_spec')
|
||||||
|
@mock.patch('kuryr_kubernetes.utils.set_lbaas_state')
|
||||||
|
@mock.patch('kuryr_kubernetes.utils.get_lbaas_state')
|
||||||
|
def test_on_present_rollback(self, m_get_lbaas_state,
|
||||||
|
m_set_lbaas_state, m_get_lbaas_spec):
|
||||||
|
m_drv_service_pub_ip = mock.Mock()
|
||||||
|
m_drv_service_pub_ip.acquire_service_pub_ip_info.return_value = None
|
||||||
|
m_drv_service_pub_ip.associate_pub_ip.return_value = True
|
||||||
|
|
||||||
|
m_handler = mock.Mock(spec=h_lb.KuryrLoadBalancerHandler)
|
||||||
|
m_handler._should_ignore.return_value = False
|
||||||
|
m_handler._sync_lbaas_members.return_value = True
|
||||||
|
m_handler._drv_service_pub_ip = m_drv_service_pub_ip
|
||||||
|
h_lb.KuryrLoadBalancerHandler.on_present(m_handler, get_lb_crd())
|
||||||
|
|
||||||
|
m_handler._should_ignore.assert_called_once_with(get_lb_crd())
|
||||||
|
m_handler._sync_lbaas_members.assert_called_once_with(
|
||||||
|
get_lb_crd())
|
||||||
|
|
||||||
|
def test_on_cascade_deleted_lb_service(self):
|
||||||
|
m_handler = mock.Mock(spec=h_lb.KuryrLoadBalancerHandler)
|
||||||
|
m_handler._drv_lbaas = mock.Mock()
|
||||||
|
m_handler._drv_service_pub_ip = mock.Mock()
|
||||||
|
crd = get_lb_crd()
|
||||||
|
m_handler._drv_lbaas.release_loadbalancer(
|
||||||
|
loadbalancer=crd['status']['loadbalancer'])
|
||||||
|
m_handler._drv_service_pub_ip.release_pub_ip(
|
||||||
|
crd['status']['service_pub_ip_info'])
|
||||||
|
|
||||||
|
def test_should_ignore(self):
|
||||||
|
m_handler = mock.Mock(spec=h_lb.KuryrLoadBalancerHandler)
|
||||||
|
m_handler._has_pods.return_value = True
|
||||||
|
|
||||||
|
ret = h_lb.KuryrLoadBalancerHandler._should_ignore(
|
||||||
|
m_handler, get_lb_crd())
|
||||||
|
self.assertEqual(False, ret)
|
||||||
|
|
||||||
|
m_handler._has_pods.assert_called_once_with(get_lb_crd())
|
||||||
|
|
||||||
|
def test_has_pods(self):
|
||||||
|
crd = get_lb_crd()
|
||||||
|
m_handler = mock.Mock(spec=h_lb.KuryrLoadBalancerHandler)
|
||||||
|
|
||||||
|
ret = h_lb.KuryrLoadBalancerHandler._has_pods(m_handler, crd)
|
||||||
|
|
||||||
|
self.assertEqual(True, ret)
|
||||||
|
|
||||||
|
def test_get_pod_subnet(self):
|
||||||
|
subnet_id = mock.sentinel.subnet_id
|
||||||
|
project_id = mock.sentinel.project_id
|
||||||
|
target_ref = {'kind': k_const.K8S_OBJ_POD,
|
||||||
|
'name': 'pod-name',
|
||||||
|
'namespace': 'default'}
|
||||||
|
ip = '1.2.3.4'
|
||||||
|
m_handler = mock.Mock(spec=h_lb.KuryrLoadBalancerHandler)
|
||||||
|
m_drv_pod_project = mock.Mock()
|
||||||
|
m_drv_pod_project.get_project.return_value = project_id
|
||||||
|
m_handler._drv_pod_project = m_drv_pod_project
|
||||||
|
m_drv_pod_subnets = mock.Mock()
|
||||||
|
m_drv_pod_subnets.get_subnets.return_value = {
|
||||||
|
subnet_id: osv_network.Network(subnets=osv_subnet.SubnetList(
|
||||||
|
objects=[osv_subnet.Subnet(cidr='1.2.3.0/24')]))}
|
||||||
|
m_handler._drv_pod_subnets = m_drv_pod_subnets
|
||||||
|
|
||||||
|
observed_subnet_id = h_lb.KuryrLoadBalancerHandler._get_pod_subnet(
|
||||||
|
m_handler, target_ref, ip)
|
||||||
|
|
||||||
|
self.assertEqual(subnet_id, observed_subnet_id)
|
||||||
|
|
||||||
|
def _sync_lbaas_members_impl(self, m_get_drv_lbaas, m_get_drv_project,
|
||||||
|
m_get_drv_subnets, subnet_id, project_id,
|
||||||
|
crd):
|
||||||
|
m_drv_lbaas = mock.Mock(wraps=FakeLBaaSDriver())
|
||||||
|
m_drv_project = mock.Mock()
|
||||||
|
m_drv_project.get_project.return_value = project_id
|
||||||
|
m_drv_subnets = mock.Mock()
|
||||||
|
m_drv_subnets.get_subnets.return_value = {
|
||||||
|
subnet_id: mock.sentinel.subnet}
|
||||||
|
m_get_drv_lbaas.return_value = m_drv_lbaas
|
||||||
|
m_get_drv_project.return_value = m_drv_project
|
||||||
|
m_get_drv_subnets.return_value = m_drv_subnets
|
||||||
|
|
||||||
|
handler = h_lb.KuryrLoadBalancerHandler()
|
||||||
|
|
||||||
|
with mock.patch.object(handler, '_get_pod_subnet') as m_get_pod_subnet:
|
||||||
|
m_get_pod_subnet.return_value = subnet_id
|
||||||
|
handler._sync_lbaas_members(crd)
|
||||||
|
|
||||||
|
lsnrs = {lsnr['id']: lsnr for lsnr in crd['status']['listeners']}
|
||||||
|
pools = {pool['id']: pool for pool in crd['status']['pools']}
|
||||||
|
observed_targets = sorted(
|
||||||
|
(str(member['ip']), (
|
||||||
|
lsnrs[pools[member['pool_id']]['listener_id']]['port'],
|
||||||
|
member['port']))
|
||||||
|
for member in crd['status']['members'])
|
||||||
|
return observed_targets
|
||||||
|
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodSubnetsDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodProjectDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.LBaaSDriver.get_instance')
|
||||||
|
def test_sync_lbaas_members(self, m_get_drv_lbaas, m_get_drv_project,
|
||||||
|
m_get_drv_subnets):
|
||||||
|
# REVISIT(ivc): test methods separately and verify ensure/release
|
||||||
|
project_id = str(uuid.uuid4())
|
||||||
|
subnet_id = str(uuid.uuid4())
|
||||||
|
expected_ip = '1.2.3.4'
|
||||||
|
expected_targets = {
|
||||||
|
'1.1.1.1': (1, 2),
|
||||||
|
'1.1.1.1': (1, 2),
|
||||||
|
'1.1.1.1': (1, 2)}
|
||||||
|
crd = get_lb_crd()
|
||||||
|
|
||||||
|
observed_targets = self._sync_lbaas_members_impl(
|
||||||
|
m_get_drv_lbaas, m_get_drv_project, m_get_drv_subnets,
|
||||||
|
subnet_id, project_id, crd)
|
||||||
|
|
||||||
|
self.assertEqual(sorted(expected_targets.items()), observed_targets)
|
||||||
|
self.assertEqual(expected_ip, str(crd['status']['loadbalancer']['ip']))
|
||||||
|
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodSubnetsDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodProjectDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.LBaaSDriver.get_instance')
|
||||||
|
def test_sync_lbaas_members_udp(self, m_get_drv_lbaas,
|
||||||
|
m_get_drv_project, m_get_drv_subnets):
|
||||||
|
# REVISIT(ivc): test methods separately and verify ensure/release
|
||||||
|
project_id = str(uuid.uuid4())
|
||||||
|
subnet_id = str(uuid.uuid4())
|
||||||
|
expected_ip = "1.2.3.4"
|
||||||
|
expected_targets = {
|
||||||
|
'1.1.1.1': (1, 2),
|
||||||
|
'1.1.1.1': (1, 2),
|
||||||
|
'1.1.1.1': (1, 2)}
|
||||||
|
|
||||||
|
crd = get_lb_crd()
|
||||||
|
|
||||||
|
observed_targets = self._sync_lbaas_members_impl(
|
||||||
|
m_get_drv_lbaas, m_get_drv_project, m_get_drv_subnets,
|
||||||
|
subnet_id, project_id, crd)
|
||||||
|
|
||||||
|
self.assertEqual(sorted(expected_targets.items()), observed_targets)
|
||||||
|
self.assertEqual(expected_ip, str(crd['status']['loadbalancer']['ip']))
|
||||||
|
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodSubnetsDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodProjectDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.LBaaSDriver.get_instance')
|
||||||
|
def test_sync_lbaas_members_svc_listener_port_edit(
|
||||||
|
self, m_get_drv_lbaas, m_get_drv_project, m_get_drv_subnets):
|
||||||
|
# REVISIT(ivc): test methods separately and verify ensure/release
|
||||||
|
project_id = str(uuid.uuid4())
|
||||||
|
subnet_id = str(uuid.uuid4())
|
||||||
|
expected_ip = '1.2.3.4'
|
||||||
|
crd = get_lb_crd()
|
||||||
|
|
||||||
|
m_drv_lbaas = mock.Mock(wraps=FakeLBaaSDriver())
|
||||||
|
m_drv_project = mock.Mock()
|
||||||
|
m_drv_project.get_project.return_value = project_id
|
||||||
|
m_drv_subnets = mock.Mock()
|
||||||
|
m_drv_subnets.get_subnets.return_value = {
|
||||||
|
subnet_id: mock.sentinel.subnet}
|
||||||
|
m_get_drv_lbaas.return_value = m_drv_lbaas
|
||||||
|
m_get_drv_project.return_value = m_drv_project
|
||||||
|
m_get_drv_subnets.return_value = m_drv_subnets
|
||||||
|
|
||||||
|
handler = h_lb.KuryrLoadBalancerHandler()
|
||||||
|
|
||||||
|
with mock.patch.object(handler, '_get_pod_subnet') as m_get_pod_subnet:
|
||||||
|
m_get_pod_subnet.return_value = subnet_id
|
||||||
|
handler._sync_lbaas_members(crd)
|
||||||
|
|
||||||
|
self.assertEqual(expected_ip, str(crd['status']['loadbalancer']['ip']))
|
||||||
|
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodSubnetsDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.PodProjectDriver.get_instance')
|
||||||
|
@mock.patch('kuryr_kubernetes.controller.drivers.base'
|
||||||
|
'.LBaaSDriver.get_instance')
|
||||||
|
def test_add_new_members_udp(self, m_get_drv_lbaas,
|
||||||
|
m_get_drv_project, m_get_drv_subnets):
|
||||||
|
project_id = str(uuid.uuid4())
|
||||||
|
subnet_id = str(uuid.uuid4())
|
||||||
|
crd = get_lb_crd()
|
||||||
|
|
||||||
|
m_drv_lbaas = mock.Mock(wraps=FakeLBaaSDriver())
|
||||||
|
m_drv_project = mock.Mock()
|
||||||
|
m_drv_project.get_project.return_value = project_id
|
||||||
|
m_drv_subnets = mock.Mock()
|
||||||
|
m_drv_subnets.get_subnets.return_value = {
|
||||||
|
subnet_id: mock.sentinel.subnet}
|
||||||
|
m_get_drv_lbaas.return_value = m_drv_lbaas
|
||||||
|
m_get_drv_project.return_value = m_drv_project
|
||||||
|
m_get_drv_subnets.return_value = m_drv_subnets
|
||||||
|
|
||||||
|
handler = h_lb.KuryrLoadBalancerHandler()
|
||||||
|
member_added = handler._add_new_members(crd)
|
||||||
|
|
||||||
|
self.assertEqual(member_added, False)
|
||||||
|
m_drv_lbaas.ensure_member.assert_not_called()
|
|
@ -20,7 +20,6 @@ from oslo_config import cfg
|
||||||
|
|
||||||
from kuryr_kubernetes import constants as k_const
|
from kuryr_kubernetes import constants as k_const
|
||||||
from kuryr_kubernetes import exceptions as k_exc
|
from kuryr_kubernetes import exceptions as k_exc
|
||||||
from kuryr_kubernetes.objects import lbaas as obj_lbaas
|
|
||||||
from kuryr_kubernetes.objects import vif
|
from kuryr_kubernetes.objects import vif
|
||||||
from kuryr_kubernetes.tests import base as test_base
|
from kuryr_kubernetes.tests import base as test_base
|
||||||
from kuryr_kubernetes.tests.unit import kuryr_fixtures as k_fix
|
from kuryr_kubernetes.tests.unit import kuryr_fixtures as k_fix
|
||||||
|
@ -185,40 +184,120 @@ class TestUtils(test_base.TestCase):
|
||||||
|
|
||||||
@mock.patch('kuryr_kubernetes.utils.get_service_ports')
|
@mock.patch('kuryr_kubernetes.utils.get_service_ports')
|
||||||
def test_has_port_changes(self, m_get_service_ports):
|
def test_has_port_changes(self, m_get_service_ports):
|
||||||
service = mock.MagicMock()
|
service = {
|
||||||
m_get_service_ports.return_value = [
|
'metadata': {
|
||||||
{'port': 1, 'name': 'X', 'protocol': 'TCP', 'targetPort': 1},
|
'selfLink': ""
|
||||||
]
|
},
|
||||||
|
'spec': {
|
||||||
lbaas_spec = mock.MagicMock()
|
'ports': [
|
||||||
lbaas_spec.ports = [
|
{
|
||||||
obj_lbaas.LBaaSPortSpec(name='X', protocol='TCP', port=1,
|
'port': 1,
|
||||||
targetPort=1),
|
'name': 'X',
|
||||||
obj_lbaas.LBaaSPortSpec(name='Y', protocol='TCP', port=2,
|
'protocol': 'TCP',
|
||||||
targetPort=2),
|
'targetPort': '1'
|
||||||
]
|
}
|
||||||
|
]
|
||||||
ret = utils.has_port_changes(service, lbaas_spec)
|
}
|
||||||
|
}
|
||||||
|
lb_crd_spec = {
|
||||||
|
'spec': {
|
||||||
|
'ports': [
|
||||||
|
{
|
||||||
|
'name': 'Y',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 2,
|
||||||
|
'targetPort': 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = utils.has_port_changes(service, lb_crd_spec)
|
||||||
self.assertTrue(ret)
|
self.assertTrue(ret)
|
||||||
|
|
||||||
@mock.patch('kuryr_kubernetes.utils.get_service_ports')
|
@mock.patch('kuryr_kubernetes.utils.get_service_ports')
|
||||||
def test_has_port_changes__no_changes(self, m_get_service_ports):
|
def test_has_port_changes_more_ports(self, m_get_service_ports):
|
||||||
service = mock.MagicMock()
|
service = {
|
||||||
m_get_service_ports.return_value = [
|
'metadata': {
|
||||||
{'port': 1, 'name': 'X', 'protocol': 'TCP', 'targetPort': '1'},
|
'selfLink': ""
|
||||||
{'port': 2, 'name': 'Y', 'protocol': 'TCP', 'targetPort': '2'}
|
},
|
||||||
]
|
'spec': {
|
||||||
|
'ports': [
|
||||||
|
{
|
||||||
|
'port': 1,
|
||||||
|
'name': 'X',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'targetPort': '1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lb_crd_spec = {
|
||||||
|
'spec': {
|
||||||
|
'ports': [
|
||||||
|
{
|
||||||
|
'name': 'X',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 1,
|
||||||
|
'targetPort': 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Y',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 2,
|
||||||
|
'targetPort': 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lbaas_spec = mock.MagicMock()
|
ret = utils.has_port_changes(service, lb_crd_spec)
|
||||||
lbaas_spec.ports = [
|
self.assertTrue(ret)
|
||||||
obj_lbaas.LBaaSPortSpec(name='X', protocol='TCP', port=1,
|
|
||||||
targetPort=1),
|
|
||||||
obj_lbaas.LBaaSPortSpec(name='Y', protocol='TCP', port=2,
|
|
||||||
targetPort=2),
|
|
||||||
]
|
|
||||||
|
|
||||||
ret = utils.has_port_changes(service, lbaas_spec)
|
@mock.patch('kuryr_kubernetes.utils.get_service_ports')
|
||||||
|
def test_has_port_changes_no_changes(self, m_get_service_ports):
|
||||||
|
|
||||||
|
service = {
|
||||||
|
'metadata': {
|
||||||
|
'selfLink': ""
|
||||||
|
},
|
||||||
|
'spec': {
|
||||||
|
'ports': [
|
||||||
|
{
|
||||||
|
'port': 1,
|
||||||
|
'name': 'X',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'targetPort': '1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Y',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 2,
|
||||||
|
'targetPort': '2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_crd_spec = {
|
||||||
|
'spec': {
|
||||||
|
'ports': [
|
||||||
|
{
|
||||||
|
'name': 'X',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 1,
|
||||||
|
'targetPort': '1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Y',
|
||||||
|
'protocol': 'TCP',
|
||||||
|
'port': 2,
|
||||||
|
'targetPort': '2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = utils.has_port_changes(service, lb_crd_spec)
|
||||||
self.assertFalse(ret)
|
self.assertFalse(ret)
|
||||||
|
|
||||||
def test_get_nodes_ips(self):
|
def test_get_nodes_ips(self):
|
||||||
|
|
|
@ -379,24 +379,27 @@ def get_endpoints_link(service):
|
||||||
return "/".join(link_parts)
|
return "/".join(link_parts)
|
||||||
|
|
||||||
|
|
||||||
def has_port_changes(service, lbaas_spec):
|
def has_port_changes(service, loadbalancer_crd):
|
||||||
|
if not loadbalancer_crd:
|
||||||
|
return False
|
||||||
link = service['metadata']['selfLink']
|
link = service['metadata']['selfLink']
|
||||||
|
svc_port_set = service['spec'].get('ports')
|
||||||
|
|
||||||
fields = obj_lbaas.LBaaSPortSpec.fields
|
for port in svc_port_set:
|
||||||
svc_port_set = {tuple(port[attr] for attr in fields)
|
port['targetPort'] = str(port['targetPort'])
|
||||||
for port in get_service_ports(service)}
|
spec_port_set = loadbalancer_crd['spec'].get('ports', [])
|
||||||
|
if spec_port_set:
|
||||||
spec_port_set = {tuple(getattr(port, attr)
|
if len(svc_port_set) != len(spec_port_set):
|
||||||
for attr in fields
|
return True
|
||||||
if port.obj_attr_is_set(attr))
|
pairs = zip(svc_port_set, spec_port_set)
|
||||||
for port in lbaas_spec.ports}
|
diff = any(x != y for x, y in pairs)
|
||||||
|
if diff:
|
||||||
if svc_port_set != spec_port_set:
|
LOG.debug("LBaaS spec ports %(spec_ports)s != %(svc_ports)s "
|
||||||
LOG.debug("LBaaS spec ports %(spec_ports)s != %(svc_ports)s "
|
"for %(link)s" % {'spec_ports': spec_port_set,
|
||||||
"for %(link)s" % {'spec_ports': spec_port_set,
|
'svc_ports': svc_port_set,
|
||||||
'svc_ports': svc_port_set,
|
'link': link})
|
||||||
'link': link})
|
return diff
|
||||||
return svc_port_set != spec_port_set
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_service_ports(service):
|
def get_service_ports(service):
|
||||||
|
|
|
@ -98,8 +98,9 @@ kuryr_kubernetes.controller.drivers.vif_pool =
|
||||||
|
|
||||||
kuryr_kubernetes.controller.handlers =
|
kuryr_kubernetes.controller.handlers =
|
||||||
vif = kuryr_kubernetes.controller.handlers.vif:VIFHandler
|
vif = kuryr_kubernetes.controller.handlers.vif:VIFHandler
|
||||||
lbaasspec = kuryr_kubernetes.controller.handlers.lbaas:LBaaSSpecHandler
|
service = kuryr_kubernetes.controller.handlers.lbaas:ServiceHandler
|
||||||
lb = kuryr_kubernetes.controller.handlers.lbaas:LoadBalancerHandler
|
endpoints = kuryr_kubernetes.controller.handlers.lbaas:EndpointsHandler
|
||||||
|
kuryrloadbalancer = kuryr_kubernetes.controller.handlers.loadbalancer:KuryrLoadBalancerHandler
|
||||||
namespace = kuryr_kubernetes.controller.handlers.namespace:NamespaceHandler
|
namespace = kuryr_kubernetes.controller.handlers.namespace:NamespaceHandler
|
||||||
policy = kuryr_kubernetes.controller.handlers.policy:NetworkPolicyHandler
|
policy = kuryr_kubernetes.controller.handlers.policy:NetworkPolicyHandler
|
||||||
pod_label = kuryr_kubernetes.controller.handlers.pod_label:PodLabelHandler
|
pod_label = kuryr_kubernetes.controller.handlers.pod_label:PodLabelHandler
|
||||||
|
|
Loading…
Reference in New Issue