diff --git a/f5lbaasdriver/v2/bigip/driver_v2.py b/f5lbaasdriver/v2/bigip/driver_v2.py index 040a71ac..3f9e3bd7 100644 --- a/f5lbaasdriver/v2/bigip/driver_v2.py +++ b/f5lbaasdriver/v2/bigip/driver_v2.py @@ -150,13 +150,13 @@ class EntityManager(object): def __init__(self, driver): self.driver = driver self.api_dict = None - self.loadbalancer = None - def _call_rpc(self, context, entity, rpc_method): + def _call_rpc(self, context, loadbalancer, entity, rpc_method, **kwargs): '''Perform operations common to create and delete for managers.''' try: - agent_host, service = self._setup_crud(context, entity) + agent_host, service = self._setup_crud( + context, loadbalancer, entity, **kwargs) rpc_callable = getattr(self.driver.agent_rpc, rpc_method) rpc_callable(context, self.api_dict, service, agent_host) except (lbaas_agentschedulerv2.NoEligibleLbaasAgent, @@ -166,7 +166,7 @@ def _call_rpc(self, context, entity, rpc_method): LOG.error("Exception: %s: %s" % (rpc_method, e)) raise e - def _setup_crud(self, context, entity): + def _setup_crud(self, context, loadbalancer, entity, **kwargs): '''Setup CRUD operations for managers to make calls to agent. :param context: auth context for performing CRUD operation @@ -175,13 +175,15 @@ def _setup_crud(self, context, entity): :raises: F5NoAttachedLoadbalancerException ''' - if entity.attached_to_loadbalancer() and self.loadbalancer: - (agent, service) = self._schedule_agent_create_service(context) + if entity.attached_to_loadbalancer() and loadbalancer: + (agent, service) = self._schedule_agent_create_service( + context, loadbalancer, entity, **kwargs) return agent['host'], service raise F5NoAttachedLoadbalancerException() - def _schedule_agent_create_service(self, context): + def _schedule_agent_create_service(self, context, loadbalancer, + entity=None, **kwargs): '''Schedule agent and build service--used for most managers. :param context: auth context for performing crud operation @@ -191,13 +193,97 @@ def _schedule_agent_create_service(self, context): agent = self.driver.scheduler.schedule( self.driver.plugin, context, - self.loadbalancer.id, + loadbalancer.id, self.driver.env ) service = self.driver.service_builder.build( - context, self.loadbalancer, agent) + context, loadbalancer, agent, **kwargs) return agent, service + def _append_listeners(self, context, service, listener): + + if not listener: + return + + def get_db_listener(): + if cfg.CONF.f5_driver_perf_mode == 3: + return listener + else: + return self.driver.plugin.db.get_listener( + context, listener.id) + + db_listener = get_db_listener() + listener_dict = db_listener.to_dict( + loadbalancer=False, + default_pool=False, + l7_policies=False + ) + + # Listener may have l7policies or default pool + listener_dict['l7_policies'] = \ + [{'id': l7_policy.id} for l7_policy in listener.l7_policies] + if listener.default_pool: + listener_dict['default_pool_id'] = listener.default_pool.id + service['listeners'] = [listener_dict] + + def _append_pools_monitors(self, context, service, pool): + + if not pool: + service['pools'] = [] + return + + def get_db_pool(): + if cfg.CONF.f5_driver_perf_mode == 3: + return pool + else: + return self.driver.plugin.db.get_pool( + context, pool.id) + + db_pool = get_db_pool() + + pool_dict = db_pool.to_dict( + healthmonitor=False, + listener=False, + listeners=False, + loadbalancer=False, + l7_policies=False, + members=False, + session_persistence=False + ) + + pool_dict['members'] = [{'id': member.id} for member in pool.members] + pool_dict['l7_policies'] = [ + {'id': l7_policy.id} for l7_policy in pool.l7_policies] + + if pool.session_persistence: + pool_dict['session_persistence'] = ( + pool.session_persistence.to_api_dict() + ) + + service['pools'] = [pool_dict] + + # Place an empty member list as the initial value. + # Append_members() can be called later to change this value. + service['members'] = [] + + if not pool.healthmonitor: + return + + def get_db_healthmonitor(): + if cfg.CONF.f5_driver_perf_mode == 3: + return pool.healthmonitor + else: + return self.driver.plugin.db.get_healthmonitor( + context, + pool.healthmonitor.id + ) + + healthmonitor = get_db_healthmonitor() + healthmonitor_dict = healthmonitor.to_dict(pool=False) + healthmonitor_dict['pool_id'] = pool.id + + service['healthmonitors'] = [healthmonitor_dict] + class LoadBalancerManager(EntityManager): """LoadBalancerManager class handles Neutron LBaaS CRUD.""" @@ -206,9 +292,9 @@ class LoadBalancerManager(EntityManager): def create(self, context, loadbalancer): """Create a loadbalancer.""" driver = self.driver - self.loadbalancer = loadbalancer try: - agent, service = self._schedule_agent_create_service(context) + agent, service = self._schedule_agent_create_service( + context, loadbalancer) agent_host = agent['host'] agent_config = agent.get('configurations', {}) LOG.debug("agent configurations: %s" % agent_config) @@ -241,7 +327,7 @@ def create(self, context, loadbalancer): if driver.unlegacy_setting_placeholder_driver_side: LOG.debug('calling extra build():') service = self.driver.service_builder.build( - context, self.loadbalancer, agent) + context, loadbalancer, agent) else: LOG.debug("Agent devices are nova managed") @@ -264,9 +350,9 @@ def create(self, context, loadbalancer): def update(self, context, old_loadbalancer, loadbalancer): """Update a loadbalancer.""" driver = self.driver - self.loadbalancer = loadbalancer try: - agent, service = self._schedule_agent_create_service(context) + agent, service = self._schedule_agent_create_service( + context, loadbalancer) agent_host = agent['host'] driver.agent_rpc.update_loadbalancer( @@ -291,9 +377,9 @@ def update(self, context, old_loadbalancer, loadbalancer): def delete(self, context, loadbalancer): """Delete a loadbalancer.""" driver = self.driver - self.loadbalancer = loadbalancer try: - agent, service = self._schedule_agent_create_service(context) + agent, service = self._schedule_agent_create_service( + context, loadbalancer) agent_host = agent['host'] driver.agent_rpc.delete_loadbalancer( @@ -350,19 +436,33 @@ class ListenerManager(EntityManager): def create(self, context, listener): """Create a listener.""" - self.loadbalancer = listener.loadbalancer + lb = listener.loadbalancer self.api_dict = listener.to_dict( loadbalancer=False, default_pool=False) - self._call_rpc(context, listener, 'create_listener') + + def append_listeners(context, loadbalancer, service): + self._append_listeners(context, service, listener) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Listener does not have default pool or l7policies. + self._call_rpc( + context, lb, listener, 'create_listener', + append_listeners=append_listeners, + append_pools_monitors=lambda *args: None, + append_members=lambda *args: None, + append_l7policies_rules=lambda *args: None + ) + else: + self._call_rpc(context, lb, listener, 'create_listener') @log_helpers.log_method_call def update(self, context, old_listener, listener): """Update a listener.""" driver = self.driver - self.loadbalancer = listener.loadbalancer + lb = listener.loadbalancer try: - agent_host, service = self._setup_crud(context, listener) + agent_host, service = self._setup_crud(context, lb, listener) driver.agent_rpc.update_listener( context, old_listener.to_dict(loadbalancer=False, @@ -379,10 +479,25 @@ def update(self, context, old_listener, listener): def delete(self, context, listener): """Delete a listener.""" - self.loadbalancer = listener.loadbalancer + lb = listener.loadbalancer self.api_dict = listener.to_dict( loadbalancer=False, default_pool=False) - self._call_rpc(context, listener, 'delete_listener') + + def append_listeners(context, lb, service): + self._append_listeners(context, service, listener) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # L7policy should already be deleted. + # Needn't modify pool. + self._call_rpc( + context, lb, listener, 'delete_listener', + append_listeners=append_listeners, + append_pools_monitors=lambda *args: None, + append_members=lambda *args: None, + append_l7policies_rules=lambda *args: None + ) + else: + self._call_rpc(context, lb, listener, 'delete_listener') class PoolManager(EntityManager): @@ -405,18 +520,37 @@ def _get_pool_dict(self, pool): def create(self, context, pool): """Create a pool.""" - self.loadbalancer = pool.loadbalancer + lb = pool.loadbalancer self.api_dict = self._get_pool_dict(pool) - self._call_rpc(context, pool, 'create_pool') + + def append_listeners(context, loadbalancer, service): + self._append_listeners(context, service, pool.listener) + + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors(context, service, pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Pool and l7plicies ??? + # Pool may be associated with listener, maybe not. + # Pool has no members + # Listener may have l7policies. Utilize default behavior. + self._call_rpc( + context, lb, pool, 'create_pool', + append_listeners=append_listeners, + append_pools_monitors=append_pools_monitors, + append_members=lambda *args: None + ) + else: + self._call_rpc(context, lb, pool, 'create_pool') @log_helpers.log_method_call def update(self, context, old_pool, pool): """Update a pool.""" driver = self.driver - self.loadbalancer = pool.loadbalancer + lb = pool.loadbalancer try: - agent_host, service = self._setup_crud(context, pool) + agent_host, service = self._setup_crud(context, lb, pool) driver.agent_rpc.update_pool( context, self._get_pool_dict(old_pool), @@ -432,9 +566,25 @@ def update(self, context, old_pool, pool): def delete(self, context, pool): """Delete a pool.""" - self.loadbalancer = pool.loadbalancer + lb = pool.loadbalancer self.api_dict = self._get_pool_dict(pool) - self._call_rpc(context, pool, 'delete_pool') + + def append_listeners(context, loadbalancer, service): + self._append_listeners(context, service, pool.listener) + + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors(context, service, pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Pool may be associated with a listener + # Utilize default behavior to load member, l7policy and rule + self._call_rpc( + context, lb, pool, 'delete_pool', + append_listeners=append_listeners, + append_pools_monitors=append_pools_monitors + ) + else: + self._call_rpc(context, lb, pool, 'delete_pool') class MemberManager(EntityManager): @@ -444,7 +594,7 @@ class MemberManager(EntityManager): def create(self, context, member): """Create a member.""" - self.loadbalancer = member.pool.loadbalancer + lb = member.pool.loadbalancer if self.driver.unlegacy_setting_placeholder_driver_side: LOG.debug('running un-legacy way for member create p1:') @@ -452,7 +602,7 @@ def create(self, context, member): subnet = driver.plugin.db._core_plugin.get_subnet( context, member.subnet_id ) - agent_host, service = self._setup_crud(context, member) + agent_host, service = self._setup_crud(context, lb, member) p = driver.plugin.db._core_plugin.create_port(context, { 'port': { 'tenant_id': subnet['tenant_id'], @@ -466,7 +616,20 @@ def create(self, context, member): portbindings.HOST_ID: agent_host}}) LOG.debug('the port created here is: %s' % p) self.api_dict = member.to_dict(pool=False) - self._call_rpc(context, member, 'create_member') + + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors(context, service, member.pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Utilize default behavior to append all members + self._call_rpc( + context, lb, member, 'create_member', + append_listeners=lambda *args: None, + append_pools_monitors=append_pools_monitors, + append_l7policies_rules=lambda *args: None + ) + else: + self._call_rpc(context, lb, member, 'create_member') if self.driver.unlegacy_setting_placeholder_driver_side: LOG.debug('running un-legacy way for member create p2:') @@ -484,9 +647,9 @@ def update(self, context, old_member, member): """Update a member.""" driver = self.driver - self.loadbalancer = member.pool.loadbalancer + lb = member.pool.loadbalancer try: - agent_host, service = self._setup_crud(context, member) + agent_host, service = self._setup_crud(context, lb, member) driver.agent_rpc.update_member( context, old_member.to_dict(pool=False), @@ -501,10 +664,22 @@ def update(self, context, old_member, member): @log_helpers.log_method_call def delete(self, context, member): """Delete a member.""" - self.loadbalancer = member.pool.loadbalancer + lb = member.pool.loadbalancer driver = self.driver try: - agent_host, service = self._setup_crud(context, member) + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors(context, service, member.pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Utilize default behavior to append all members + agent_host, service = self._setup_crud( + context, lb, member, + append_listeners=lambda *args: None, + append_pools_monitors=append_pools_monitors, + append_l7policies_rules=lambda *args: None + ) + else: + agent_host, service = self._setup_crud(context, lb, member) driver.agent_rpc.delete_member( context, member.to_dict(pool=False), service, agent_host) @@ -520,18 +695,32 @@ class HealthMonitorManager(EntityManager): def create(self, context, health_monitor): """Create a health monitor.""" - self.loadbalancer = health_monitor.pool.loadbalancer + lb = health_monitor.pool.loadbalancer self.api_dict = health_monitor.to_dict(pool=False) - self._call_rpc(context, health_monitor, 'create_health_monitor') + + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors(context, service, health_monitor.pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Utilize default behavior to append all members + self._call_rpc( + context, lb, health_monitor, 'create_health_monitor', + append_listeners=lambda *args: None, + append_pools_monitors=append_pools_monitors, + append_l7policies_rules=lambda *args: None + ) + else: + self._call_rpc(context, lb, health_monitor, + 'create_health_monitor') @log_helpers.log_method_call def update(self, context, old_health_monitor, health_monitor): """Update a health monitor.""" driver = self.driver - self.loadbalancer = health_monitor.pool.loadbalancer + lb = health_monitor.pool.loadbalancer try: - agent_host, service = self._setup_crud(context, health_monitor) + agent_host, service = self._setup_crud(context, lb, health_monitor) driver.agent_rpc.update_health_monitor( context, old_health_monitor.to_dict(pool=False), @@ -547,9 +736,23 @@ def update(self, context, old_health_monitor, health_monitor): def delete(self, context, health_monitor): """Delete a health monitor.""" - self.loadbalancer = health_monitor.pool.loadbalancer + lb = health_monitor.pool.loadbalancer self.api_dict = health_monitor.to_dict(pool=False) - self._call_rpc(context, health_monitor, 'delete_health_monitor') + + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors(context, service, health_monitor.pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Utilize default behavior to append all members + self._call_rpc( + context, lb, health_monitor, 'delete_health_monitor', + append_listeners=lambda *args: None, + append_pools_monitors=append_pools_monitors, + append_l7policies_rules=lambda *args: None + ) + else: + self._call_rpc(context, lb, health_monitor, + 'delete_health_monitor') class L7PolicyManager(EntityManager): @@ -559,18 +762,36 @@ class L7PolicyManager(EntityManager): def create(self, context, policy): """Create an L7 policy.""" - self.loadbalancer = policy.listener.loadbalancer + lb = policy.listener.loadbalancer self.api_dict = policy.to_dict(listener=False, rules=False) - self._call_rpc(context, policy, 'create_l7policy') + + def append_listeners(context, loadbalancer, service): + self._append_listeners(context, service, policy.listener) + + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors( + context, service, policy.listener.default_pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Utilize default behavior to load policies and rules + # Listener may have default pool + # Utilize default behavior to load members + self._call_rpc( + context, lb, policy, 'create_l7policy', + append_listeners=append_listeners, + append_pools_monitors=append_pools_monitors + ) + else: + self._call_rpc(context, lb, policy, 'create_l7policy') @log_helpers.log_method_call def update(self, context, old_policy, policy): """Update a policy.""" driver = self.driver - self.loadbalancer = policy.listener.loadbalancer + lb = policy.listener.loadbalancer try: - agent_host, service = self._setup_crud(context, policy) + agent_host, service = self._setup_crud(context, lb, policy) driver.agent_rpc.update_l7policy( context, old_policy.to_dict(listener=False), @@ -586,9 +807,27 @@ def update(self, context, old_policy, policy): def delete(self, context, policy): """Delete a policy.""" - self.loadbalancer = policy.listener.loadbalancer + lb = policy.listener.loadbalancer self.api_dict = policy.to_dict(listener=False, rules=False) - self._call_rpc(context, policy, 'delete_l7policy') + + def append_listeners(context, loadbalancer, service): + self._append_listeners(context, service, policy.listener) + + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors( + context, service, policy.listener.default_pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Utilize default behavior to load policies and rules + # Listener may have default pool + # Utilize default behavior to load members + self._call_rpc( + context, lb, policy, 'delete_l7policy', + append_listeners=append_listeners, + append_pools_monitors=append_pools_monitors + ) + else: + self._call_rpc(context, lb, policy, 'delete_l7policy') class L7RuleManager(EntityManager): @@ -598,18 +837,36 @@ class L7RuleManager(EntityManager): def create(self, context, rule): """Create an L7 rule.""" - self.loadbalancer = rule.policy.listener.loadbalancer + lb = rule.policy.listener.loadbalancer self.api_dict = rule.to_dict(policy=False) - self._call_rpc(context, rule, 'create_l7rule') + + def append_listeners(context, loadbalancer, service): + self._append_listeners(context, service, rule.policy.listener) + + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors( + context, service, rule.policy.listener.default_pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Utilize default behavior to load policies and rules + # Listener may have default pool + # Utilize default behavior to load members + self._call_rpc( + context, lb, rule, 'create_l7rule', + append_listeners=append_listeners, + append_pools_monitors=append_pools_monitors + ) + else: + self._call_rpc(context, lb, rule, 'create_l7rule') @log_helpers.log_method_call def update(self, context, old_rule, rule): """Update a rule.""" driver = self.driver - self.loadbalancer = rule.policy.listener.loadbalancer + lb = rule.policy.listener.loadbalancer try: - agent_host, service = self._setup_crud(context, rule) + agent_host, service = self._setup_crud(context, lb, rule) driver.agent_rpc.update_l7rule( context, old_rule.to_dict(policy=False), @@ -625,6 +882,24 @@ def update(self, context, old_rule, rule): def delete(self, context, rule): """Delete a rule.""" - self.loadbalancer = rule.policy.listener.loadbalancer + lb = rule.policy.listener.loadbalancer self.api_dict = rule.to_dict(policy=False) - self._call_rpc(context, rule, 'delete_l7rule') + + def append_listeners(context, loadbalancer, service): + self._append_listeners(context, service, rule.policy.listener) + + def append_pools_monitors(context, loadbalancer, service): + self._append_pools_monitors( + context, service, rule.policy.listener.default_pool) + + if cfg.CONF.f5_driver_perf_mode in (2, 3): + # Utilize default behavior to load policies and rules + # Listener may have default pool + # Utilize default behavior to load members + self._call_rpc( + context, lb, rule, 'delete_l7rule', + append_listeners=append_listeners, + append_pools_monitors=append_pools_monitors + ) + else: + self._call_rpc(context, lb, rule, 'delete_l7rule') diff --git a/f5lbaasdriver/v2/bigip/service_builder.py b/f5lbaasdriver/v2/bigip/service_builder.py index a3fc5a05..b67d3324 100644 --- a/f5lbaasdriver/v2/bigip/service_builder.py +++ b/f5lbaasdriver/v2/bigip/service_builder.py @@ -53,7 +53,7 @@ def __init__(self, driver): self.disconnected_service = DisconnectedService() self.q_client = q_client.F5NetworksNeutronClient(self.plugin) - def build(self, context, loadbalancer, agent): + def build(self, context, loadbalancer, agent, **kwargs): """Get full service definition from loadbalancer ID.""" # Invalidate cache if it is too old if ((datetime.datetime.now() - self.last_cache_update).seconds > @@ -146,24 +146,45 @@ def build(self, context, loadbalancer, agent): ) # Get listeners and pools. - service['listeners'] = self._get_listeners(context, loadbalancer) + append_listeners = kwargs.get( + "append_listeners", self._append_listeners) + append_pools_monitors = kwargs.get( + "append_pools_monitors", self._append_pools_monitors) + append_members = kwargs.get("append_members", self._append_members) + append_l7policies_rules = kwargs.get( + "append_l7policies_rules", self._append_l7policies_rules) + + append_listeners(context, loadbalancer, service) + append_pools_monitors(context, loadbalancer, service) + append_members( + context, loadbalancer, service, network_map, subnet_map) + append_l7policies_rules(context, loadbalancer, service) - service['pools'], service['healthmonitors'] = \ - self._get_pools_and_healthmonitors(context, loadbalancer) + return service - service['members'] = self._get_members( - context, loadbalancer, service['pools'], - subnet_map, network_map) + @log_helpers.log_method_call + def _append_listeners(self, context, loadbalancer, service): + service['listeners'] = self._get_listeners(context, loadbalancer) - service['subnets'] = subnet_map - service['networks'] = network_map + @log_helpers.log_method_call + def _append_pools_monitors(self, context, loadbalancer, service): + service['pools'], service['healthmonitors'] = \ + self._get_pools_and_healthmonitors(context, loadbalancer) - service['l7policies'] = self._get_l7policies( - context, loadbalancer, service['listeners']) - service['l7policy_rules'] = self._get_l7policy_rules( - context, loadbalancer, service['l7policies']) + @log_helpers.log_method_call + def _append_members(self, context, loadbalancer, service, + network_map, subnet_map): + service['members'] = self._get_members( + context, loadbalancer, service['pools'], subnet_map, network_map) + service['subnets'] = subnet_map + service['networks'] = network_map - return service + @log_helpers.log_method_call + def _append_l7policies_rules(self, context, loadbalancer, service): + service['l7policies'] = self._get_l7policies( + context, loadbalancer, service['listeners']) + service['l7policy_rules'] = self._get_l7policy_rules( + context, loadbalancer, service['l7policies']) @log_helpers.log_method_call def _get_extended_member(self, context, member):