def batch_update_members(self, old_members, new_members, updated_members): updated_members = [(provider_utils.db_member_to_provider_member( self._member_repo.get(db_apis.get_session(), id=m.get(constants.ID))).to_dict(), m) for m in updated_members] provider_old_members = [ provider_utils.db_member_to_provider_member( self._member_repo.get(db_apis.get_session(), id=m.get(constants.ID))).to_dict() for m in old_members ] if old_members: pool = self._pool_repo.get(db_apis.get_session(), id=old_members[0][constants.POOL_ID]) elif new_members: pool = self._pool_repo.get(db_apis.get_session(), id=new_members[0][constants.POOL_ID]) else: pool = self._pool_repo.get( db_apis.get_session(), id=updated_members[0][0][constants.POOL_ID]) load_balancer = pool.load_balancer listeners_dicts = ( provider_utils.db_listeners_to_provider_dicts_list_of_dicts( pool.listeners)) provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( load_balancer).to_dict() store = { constants.LISTENERS: listeners_dicts, constants.LOADBALANCER_ID: load_balancer.id, constants.LOADBALANCER: provider_lb, constants.POOL_ID: pool.id, constants.PROJECT_ID: load_balancer.project_id } if load_balancer.availability_zone: store[constants.AVAILABILITY_ZONE] = ( self._az_repo.get_availability_zone_metadata_dict( db_apis.get_session(), load_balancer.availability_zone)) else: store[constants.AVAILABILITY_ZONE] = {} batch_update_members_tf = self._taskflow_load( self._member_flows.get_batch_update_members_flow( provider_old_members, new_members, updated_members), store=store) with tf_logging.DynamicLoggingListener(batch_update_members_tf, log=LOG): batch_update_members_tf.run()
def process_get(get_data): session = db_api.get_session() if get_data[constants.OBJECT] == lib_consts.LOADBALANCERS: lb_repo = repositories.LoadBalancerRepository() db_lb = lb_repo.get(session, id=get_data[lib_consts.ID], show_deleted=False) if db_lb: provider_lb = ( driver_utils.db_loadbalancer_to_provider_loadbalancer(db_lb)) return provider_lb.to_dict(recurse=True, render_unsets=True) elif get_data[constants.OBJECT] == lib_consts.LISTENERS: listener_repo = repositories.ListenerRepository() db_listener = listener_repo.get( session, id=get_data[lib_consts.ID], show_deleted=False) if db_listener: provider_listener = ( driver_utils.db_listener_to_provider_listener(db_listener)) return provider_listener.to_dict(recurse=True, render_unsets=True) elif get_data[constants.OBJECT] == lib_consts.POOLS: pool_repo = repositories.PoolRepository() db_pool = pool_repo.get(session, id=get_data[lib_consts.ID], show_deleted=False) if db_pool: provider_pool = ( driver_utils.db_pool_to_provider_pool(db_pool)) return provider_pool.to_dict(recurse=True, render_unsets=True) elif get_data[constants.OBJECT] == lib_consts.MEMBERS: member_repo = repositories.MemberRepository() db_member = member_repo.get(session, id=get_data[lib_consts.ID], show_deleted=False) if db_member: provider_member = ( driver_utils.db_member_to_provider_member(db_member)) return provider_member.to_dict(recurse=True, render_unsets=True) elif get_data[constants.OBJECT] == lib_consts.HEALTHMONITORS: hm_repo = repositories.HealthMonitorRepository() db_hm = hm_repo.get(session, id=get_data[lib_consts.ID], show_deleted=False) if db_hm: provider_hm = ( driver_utils.db_HM_to_provider_HM(db_hm)) return provider_hm.to_dict(recurse=True, render_unsets=True) elif get_data[constants.OBJECT] == lib_consts.L7POLICIES: l7policy_repo = repositories.L7PolicyRepository() db_l7policy = l7policy_repo.get(session, id=get_data[lib_consts.ID], show_deleted=False) if db_l7policy: provider_l7policy = ( driver_utils.db_l7policy_to_provider_l7policy(db_l7policy)) return provider_l7policy.to_dict(recurse=True, render_unsets=True) elif get_data[constants.OBJECT] == lib_consts.L7RULES: l7rule_repo = repositories.L7RuleRepository() db_l7rule = l7rule_repo.get(session, id=get_data[lib_consts.ID], show_deleted=False) if db_l7rule: provider_l7rule = ( driver_utils.db_l7rule_to_provider_l7rule(db_l7rule)) return provider_l7rule.to_dict(recurse=True, render_unsets=True) return {}
def delete(self, id): """Deletes a pool member.""" context = pecan.request.context.get('octavia_context') db_member = self._get_db_member(context.session, id, show_deleted=False) pool = self.repositories.pool.get(context.session, id=db_member.pool_id) project_id, provider = self._get_lb_project_id_provider( context.session, pool.load_balancer_id) self._auth_validate_action(context, project_id, constants.RBAC_DELETE) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) with db_api.get_lock_session() as lock_session: self._test_lb_and_listener_and_pool_statuses(lock_session, member=db_member) self.repositories.member.update( lock_session, db_member.id, provisioning_status=constants.PENDING_DELETE) LOG.info("Sending delete Member %s to provider %s", id, driver.name) provider_member = ( driver_utils.db_member_to_provider_member(db_member)) driver_utils.call_provider(driver.name, driver.member_delete, provider_member)
def delete(self, id): """Deletes a pool member.""" context = pecan.request.context.get('octavia_context') db_member = self._get_db_member(context.session, id, show_deleted=False) pool = self.repositories.pool.get(context.session, id=db_member.pool_id) project_id, provider = self._get_lb_project_id_provider( context.session, pool.load_balancer_id) self._auth_validate_action(context, project_id, constants.RBAC_DELETE) self._validate_pool_id(id, db_member.pool_id) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) with db_api.get_lock_session() as lock_session: self._test_lb_and_listener_and_pool_statuses(lock_session, member=db_member) self.repositories.member.update( lock_session, db_member.id, provisioning_status=constants.PENDING_DELETE) LOG.info("Sending delete Member %s to provider %s", id, driver.name) provider_member = ( driver_utils.db_member_to_provider_member(db_member)) driver_utils.call_provider(driver.name, driver.member_delete, provider_member)
def post(self, member_): """Creates a pool member on a pool.""" member = member_.member context = pecan.request.context.get('octavia_context') validate.ip_not_reserved(member.address) # Validate member subnet if member.subnet_id and not validate.subnet_exists(member.subnet_id): raise exceptions.NotFound(resource='Subnet', id=member.subnet_id) pool = self.repositories.pool.get(context.session, id=self.pool_id) member.project_id, provider = self._get_lb_project_id_provider( context.session, pool.load_balancer_id) self._auth_validate_action(context, member.project_id, constants.RBAC_POST) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) lock_session = db_api.get_session(autocommit=False) try: if self.repositories.check_clusterquota_met( lock_session, data_models.Member, base_res_id=self.pool_id): raise exceptions.ClusterQuotaException( resource=data_models.Member._name()) if self.repositories.check_quota_met(context.session, lock_session, data_models.Member, member.project_id): raise exceptions.QuotaException( resource=data_models.Member._name()) member_dict = db_prepare.create_member( member.to_dict(render_unsets=True), self.pool_id, bool(pool.health_monitor)) self._test_lb_and_listener_and_pool_statuses(lock_session) db_member = self._validate_create_member(lock_session, member_dict) # Prepare the data for the driver data model provider_member = ( driver_utils.db_member_to_provider_member(db_member)) # Dispatch to the driver LOG.info("Sending create Member %s to provider %s", db_member.id, driver.name) driver_utils.call_provider(driver.name, driver.member_create, provider_member) lock_session.commit() except Exception: with excutils.save_and_reraise_exception(): lock_session.rollback() db_member = self._get_db_member(context.session, db_member.id) result = self._convert_db_to_type(db_member, member_types.MemberResponse) return member_types.MemberRootResponse(member=result)
def post(self, member_): """Creates a pool member on a pool.""" member = member_.member context = pecan.request.context.get('octavia_context') validate.ip_not_reserved(member.address) # Validate member subnet if member.subnet_id and not validate.subnet_exists(member.subnet_id): raise exceptions.NotFound(resource='Subnet', id=member.subnet_id) pool = self.repositories.pool.get(context.session, id=self.pool_id) member.project_id, provider = self._get_lb_project_id_provider( context.session, pool.load_balancer_id) self._auth_validate_action(context, member.project_id, constants.RBAC_POST) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) lock_session = db_api.get_session(autocommit=False) try: if self.repositories.check_quota_met( context.session, lock_session, data_models.Member, member.project_id): raise exceptions.QuotaException( resource=data_models.Member._name()) member_dict = db_prepare.create_member(member.to_dict( render_unsets=True), self.pool_id, bool(pool.health_monitor)) self._test_lb_and_listener_and_pool_statuses(lock_session) db_member = self._validate_create_member(lock_session, member_dict) # Prepare the data for the driver data model provider_member = ( driver_utils.db_member_to_provider_member(db_member)) # Dispatch to the driver LOG.info("Sending create Member %s to provider %s", db_member.id, driver.name) driver_utils.call_provider( driver.name, driver.member_create, provider_member) lock_session.commit() except Exception: with excutils.save_and_reraise_exception(): lock_session.rollback() db_member = self._get_db_member(context.session, db_member.id) result = self._convert_db_to_type(db_member, member_types.MemberResponse) return member_types.MemberRootResponse(member=result)
def put(self, id, member_): """Updates a pool member.""" member = member_.member context = pecan_request.context.get('octavia_context') db_member = self._get_db_member(context.session, id, show_deleted=False) pool = self.repositories.pool.get(context.session, id=db_member.pool_id) project_id, provider = self._get_lb_project_id_provider( context.session, pool.load_balancer_id) self._auth_validate_action(context, project_id, constants.RBAC_PUT) self._validate_pool_id(id, db_member.pool_id) self._set_default_on_none(member) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) with db_api.get_lock_session() as lock_session: self._test_lb_and_listener_and_pool_statuses(lock_session, member=db_member) # Prepare the data for the driver data model member_dict = member.to_dict(render_unsets=False) member_dict['id'] = id provider_member_dict = ( driver_utils.member_dict_to_provider_dict(member_dict)) # Also prepare the baseline object data old_provider_member = driver_utils.db_member_to_provider_member( db_member) # Dispatch to the driver LOG.info("Sending update Member %s to provider %s", id, driver.name) driver_utils.call_provider( driver.name, driver.member_update, old_provider_member, driver_dm.Member.from_dict(provider_member_dict)) # Update the database to reflect what the driver just accepted member.provisioning_status = constants.PENDING_UPDATE db_member_dict = member.to_dict(render_unsets=False) self.repositories.member.update(lock_session, id, **db_member_dict) # Force SQL alchemy to query the DB, otherwise we get inconsistent # results context.session.expire_all() db_member = self._get_db_member(context.session, id) result = self._convert_db_to_type(db_member, member_types.MemberResponse) return member_types.MemberRootResponse(member=result)
def put(self, id, member_): """Updates a pool member.""" member = member_.member context = pecan.request.context.get('octavia_context') db_member = self._get_db_member(context.session, id, show_deleted=False) pool = self.repositories.pool.get(context.session, id=db_member.pool_id) project_id, provider = self._get_lb_project_id_provider( context.session, pool.load_balancer_id) self._auth_validate_action(context, project_id, constants.RBAC_PUT) self._validate_pool_id(id, db_member.pool_id) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) with db_api.get_lock_session() as lock_session: self._test_lb_and_listener_and_pool_statuses(lock_session, member=db_member) # Prepare the data for the driver data model member_dict = member.to_dict(render_unsets=False) member_dict['id'] = id provider_member_dict = ( driver_utils.member_dict_to_provider_dict(member_dict)) # Also prepare the baseline object data old_provider_member = driver_utils.db_member_to_provider_member( db_member) # Dispatch to the driver LOG.info("Sending update Member %s to provider %s", id, driver.name) driver_utils.call_provider( driver.name, driver.member_update, old_provider_member, driver_dm.Member.from_dict(provider_member_dict)) # Update the database to reflect what the driver just accepted member.provisioning_status = constants.PENDING_UPDATE db_member_dict = member.to_dict(render_unsets=False) self.repositories.member.update(lock_session, id, **db_member_dict) # Force SQL alchemy to query the DB, otherwise we get inconsistent # results context.session.expire_all() db_member = self._get_db_member(context.session, id) result = self._convert_db_to_type(db_member, member_types.MemberResponse) return member_types.MemberRootResponse(member=result)
def batch_update_members(self, old_members, new_members, updated_members): updated_members = [ (provider_utils.db_member_to_provider_member( self._member_repo.get(db_apis.get_session(), id=m.get(constants.ID))).to_dict(), m) for m in updated_members] provider_old_members = [ provider_utils.db_member_to_provider_member( self._member_repo.get(db_apis.get_session(), id=m.get(constants.ID))).to_dict() for m in old_members] if old_members: pool = self._pool_repo.get(db_apis.get_session(), id=old_members[0][constants.POOL_ID]) elif new_members: pool = self._pool_repo.get(db_apis.get_session(), id=new_members[0][constants.POOL_ID]) else: pool = self._pool_repo.get( db_apis.get_session(), id=updated_members[0][0][constants.POOL_ID]) load_balancer = pool.load_balancer listeners_dicts = ( provider_utils.db_listeners_to_provider_dicts_list_of_dicts( pool.listeners)) batch_update_members_tf = self._taskflow_load( self._member_flows.get_batch_update_members_flow( provider_old_members, new_members, updated_members), store={constants.LISTENERS: listeners_dicts, constants.LOADBALANCER: load_balancer, constants.LOADBALANCER_ID: load_balancer.id, constants.POOL_ID: pool.id, constants.PROJECT_ID: load_balancer.project_id}) with tf_logging.DynamicLoggingListener(batch_update_members_tf, log=LOG): batch_update_members_tf.run()
def put(self, members_): """Updates all members.""" members = members_.members context = pecan.request.context.get('octavia_context') db_pool = self._get_db_pool(context.session, self.pool_id) old_members = db_pool.members project_id, provider = self._get_lb_project_id_provider( context.session, db_pool.load_balancer_id) # Check POST+PUT+DELETE since this operation is all of 'CUD' self._auth_validate_action(context, project_id, constants.RBAC_POST) self._auth_validate_action(context, project_id, constants.RBAC_PUT) self._auth_validate_action(context, project_id, constants.RBAC_DELETE) # Validate member subnets for member in members: if member.subnet_id and not validate.subnet_exists( member.subnet_id): raise exceptions.NotFound(resource='Subnet', id=member.subnet_id) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) with db_api.get_lock_session() as lock_session: self._test_lb_and_listener_and_pool_statuses(lock_session) member_count_diff = len(members) - len(old_members) if member_count_diff > 0 and self.repositories.check_quota_met( context.session, lock_session, data_models.Member, db_pool.project_id, count=member_count_diff): raise exceptions.QuotaException( resource=data_models.Member._name()) old_member_uniques = {(m.ip_address, m.protocol_port): m.id for m in old_members} new_member_uniques = [(m.address, m.protocol_port) for m in members] # Find members that are brand new or updated new_members = [] updated_members = [] for m in members: if (m.address, m.protocol_port) not in old_member_uniques: validate.ip_not_reserved(m.address) new_members.append(m) else: m.id = old_member_uniques[(m.address, m.protocol_port)] updated_members.append(m) # Find members that are deleted deleted_members = [] for m in old_members: if (m.ip_address, m.protocol_port) not in new_member_uniques: deleted_members.append(m) provider_members = [] # Create new members for m in new_members: m = m.to_dict(render_unsets=False) m['project_id'] = db_pool.project_id created_member = self._graph_create(lock_session, m) provider_member = driver_utils.db_member_to_provider_member( created_member) provider_members.append(provider_member) # Update old members for m in updated_members: m.provisioning_status = constants.PENDING_UPDATE db_member_dict = m.to_dict(render_unsets=False) db_member_dict.pop('id') self.repositories.member.update(lock_session, m.id, **db_member_dict) m.pool_id = self.pool_id provider_members.append( driver_utils.db_member_to_provider_member(m)) # Delete old members for m in deleted_members: self.repositories.member.update( lock_session, m.id, provisioning_status=constants.PENDING_DELETE) # Dispatch to the driver LOG.info("Sending Pool %s batch member update to provider %s", db_pool.id, driver.name) driver_utils.call_provider(driver.name, driver.member_batch_update, provider_members)
def put(self, members_): """Updates all members.""" members = members_.members context = pecan.request.context.get('octavia_context') db_pool = self._get_db_pool(context.session, self.pool_id) old_members = db_pool.members project_id, provider = self._get_lb_project_id_provider( context.session, db_pool.load_balancer_id) # Check POST+PUT+DELETE since this operation is all of 'CUD' self._auth_validate_action(context, project_id, constants.RBAC_POST) self._auth_validate_action(context, project_id, constants.RBAC_PUT) self._auth_validate_action(context, project_id, constants.RBAC_DELETE) # Validate member subnets for member in members: if member.subnet_id and not validate.subnet_exists( member.subnet_id): raise exceptions.NotFound(resource='Subnet', id=member.subnet_id) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) with db_api.get_lock_session() as lock_session: self._test_lb_and_listener_and_pool_statuses(lock_session) member_count_diff = len(members) - len(old_members) if member_count_diff > 0 and self.repositories.check_quota_met( context.session, lock_session, data_models.Member, db_pool.project_id, count=member_count_diff): raise exceptions.QuotaException( resource=data_models.Member._name()) old_member_uniques = { (m.ip_address, m.protocol_port): m.id for m in old_members} new_member_uniques = [ (m.address, m.protocol_port) for m in members] # Find members that are brand new or updated new_members = [] updated_members = [] for m in members: if (m.address, m.protocol_port) not in old_member_uniques: validate.ip_not_reserved(m.address) new_members.append(m) else: m.id = old_member_uniques[(m.address, m.protocol_port)] updated_members.append(m) # Find members that are deleted deleted_members = [] for m in old_members: if (m.ip_address, m.protocol_port) not in new_member_uniques: deleted_members.append(m) provider_members = [] # Create new members for m in new_members: m = m.to_dict(render_unsets=False) m['project_id'] = db_pool.project_id created_member = self._graph_create(lock_session, m) provider_member = driver_utils.db_member_to_provider_member( created_member) provider_members.append(provider_member) # Update old members for m in updated_members: m.provisioning_status = constants.PENDING_UPDATE db_member_dict = m.to_dict(render_unsets=False) db_member_dict.pop('id') self.repositories.member.update( lock_session, m.id, **db_member_dict) m.pool_id = self.pool_id provider_members.append( driver_utils.db_member_to_provider_member(m)) # Delete old members for m in deleted_members: self.repositories.member.update( lock_session, m.id, provisioning_status=constants.PENDING_DELETE) # Dispatch to the driver LOG.info("Sending Pool %s batch member update to provider %s", db_pool.id, driver.name) driver_utils.call_provider( driver.name, driver.member_batch_update, provider_members)
def put(self, additive_only=False, members_=None): """Updates all members.""" members = members_.members additive_only = strutils.bool_from_string(additive_only) context = pecan_request.context.get('octavia_context') db_pool = self._get_db_pool(context.session, self.pool_id) old_members = db_pool.members project_id, provider = self._get_lb_project_id_provider( context.session, db_pool.load_balancer_id) # Check POST+PUT+DELETE since this operation is all of 'CUD' self._auth_validate_action(context, project_id, constants.RBAC_POST) self._auth_validate_action(context, project_id, constants.RBAC_PUT) if not additive_only: self._auth_validate_action(context, project_id, constants.RBAC_DELETE) # Validate member subnets for member in members: if member.subnet_id and not validate.subnet_exists( member.subnet_id, context=context): raise exceptions.NotFound(resource='Subnet', id=member.subnet_id) # Load the driver early as it also provides validation driver = driver_factory.get_driver(provider) with db_api.get_lock_session() as lock_session: self._test_lb_and_listener_and_pool_statuses(lock_session) old_member_uniques = {(m.ip_address, m.protocol_port): m.id for m in old_members} new_member_uniques = [(m.address, m.protocol_port) for m in members] # Find members that are brand new or updated new_members = [] updated_members = [] for m in members: if (m.address, m.protocol_port) not in old_member_uniques: validate.ip_not_reserved(m.address) new_members.append(m) else: m.id = old_member_uniques[(m.address, m.protocol_port)] updated_members.append(m) # Find members that are deleted deleted_members = [] for m in old_members: if (m.ip_address, m.protocol_port) not in new_member_uniques: deleted_members.append(m) if not (deleted_members or new_members or updated_members): LOG.info("Member batch update is a noop, rolling back and " "returning early.") lock_session.rollback() return if additive_only: member_count_diff = len(new_members) else: member_count_diff = len(new_members) - len(deleted_members) if member_count_diff > 0 and self.repositories.check_quota_met( context.session, lock_session, data_models.Member, db_pool.project_id, count=member_count_diff): raise exceptions.QuotaException( resource=data_models.Member._name()) provider_members = [] # Create new members for m in new_members: m = m.to_dict(render_unsets=False) m['project_id'] = db_pool.project_id created_member = self._graph_create(lock_session, m) provider_member = driver_utils.db_member_to_provider_member( created_member) provider_members.append(provider_member) # Update old members for m in updated_members: m.provisioning_status = constants.PENDING_UPDATE m.project_id = db_pool.project_id db_member_dict = m.to_dict(render_unsets=False) db_member_dict.pop('id') self.repositories.member.update(lock_session, m.id, **db_member_dict) m.pool_id = self.pool_id provider_members.append( driver_utils.db_member_to_provider_member(m)) # Delete old members for m in deleted_members: if additive_only: # Members are appended to the dict and their status remains # unchanged, because they are logically "untouched". db_member_dict = m.to_dict(render_unsets=False) db_member_dict.pop('id') m.pool_id = self.pool_id provider_members.append( driver_utils.db_member_to_provider_member(m)) else: # Members are changed to PENDING_DELETE and not passed. self.repositories.member.update( lock_session, m.id, provisioning_status=constants.PENDING_DELETE) # Dispatch to the driver LOG.info("Sending Pool %s batch member update to provider %s", db_pool.id, driver.name) driver_utils.call_provider(driver.name, driver.member_batch_update, db_pool.id, provider_members)