# Copyright (c) 2015 OpenStack Foundation # 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 networking_odl.common import constants as odl_const from networking_odl.db import db def _is_valid_update_operation(session, row): # Check if there are older updates in the queue if db.check_for_older_ops(session, row): return False # Check for a pending or processing create operation on this uuid if db.check_for_pending_or_processing_ops( session, row.object_uuid, odl_const.ODL_CREATE): return False return True def validate_network_operation(session, row): """Validate the network operation based on dependencies. Validate network operation depending on whether it's dependencies are still in 'pending' or 'processing' state. e.g. """ if row.operation == odl_const.ODL_DELETE: # Check for any pending or processing create or update # ops on this uuid itself if db.check_for_pending_or_processing_ops( session, row.object_uuid, [odl_const.ODL_UPDATE, odl_const.ODL_CREATE]): return False # Check for dependent operations if db.check_for_pending_delete_ops_with_parent( session, odl_const.ODL_SUBNET, row.object_uuid): return False if db.check_for_pending_delete_ops_with_parent( session, odl_const.ODL_PORT, row.object_uuid): return False if db.check_for_pending_delete_ops_with_parent( session, odl_const.ODL_ROUTER, row.object_uuid): return False elif (row.operation == odl_const.ODL_UPDATE and not _is_valid_update_operation(session, row)): return False return True def validate_subnet_operation(session, row): """Validate the subnet operation based on dependencies. Validate subnet operation depending on whether it's dependencies are still in 'pending' or 'processing' state. e.g. """ if row.operation in (odl_const.ODL_CREATE, odl_const.ODL_UPDATE): network_id = row.data['network_id'] # Check for pending or processing network operations if db.check_for_pending_or_processing_ops(session, network_id): return False if (row.operation == odl_const.ODL_UPDATE and not _is_valid_update_operation(session, row)): return False elif row.operation == odl_const.ODL_DELETE: # Check for any pending or processing create or update # ops on this uuid itself if db.check_for_pending_or_processing_ops( session, row.object_uuid, [odl_const.ODL_UPDATE, odl_const.ODL_CREATE]): return False # Check for dependent operations if db.check_for_pending_delete_ops_with_parent( session, odl_const.ODL_PORT, row.object_uuid): return False return True def validate_port_operation(session, row): """Validate port operation based on dependencies. Validate port operation depending on whether it's dependencies are still in 'pending' or 'processing' state. e.g. """ if row.operation in (odl_const.ODL_CREATE, odl_const.ODL_UPDATE): network_id = row.data['network_id'] # Check for pending or processing network operations ops = db.check_for_pending_or_processing_ops(session, network_id) # Check for pending subnet operations. for fixed_ip in row.data['fixed_ips']: ip_ops = db.check_for_pending_or_processing_ops( session, fixed_ip['subnet_id']) ops = ops or ip_ops if ops: return False if (row.operation == odl_const.ODL_UPDATE and not _is_valid_update_operation(session, row)): return False elif row.operation == odl_const.ODL_DELETE: # Check for any pending or processing create or update # ops on this uuid itself if db.check_for_pending_or_processing_ops( session, row.object_uuid, [odl_const.ODL_UPDATE, odl_const.ODL_CREATE]): return False return True def validate_router_operation(session, row): """Validate router operation based on dependencies. Validate router operation depending on whether it's dependencies are still in 'pending' or 'processing' state. """ if row.operation in (odl_const.ODL_CREATE, odl_const.ODL_UPDATE): if row.data['gw_port_id'] is not None: if db.check_for_pending_or_processing_ops(session, row.data['gw_port_id']): return False if (row.operation == odl_const.ODL_UPDATE and not _is_valid_update_operation(session, row)): return False elif row.operation == odl_const.ODL_DELETE: # Check for any pending or processing create or update # operations on this uuid. if db.check_for_pending_or_processing_ops(session, row.object_uuid, [odl_const.ODL_UPDATE, odl_const.ODL_CREATE]): return False # Check that dependent port delete operation has completed. if db.check_for_pending_delete_ops_with_parent( session, odl_const.ODL_PORT, row.object_uuid): return False # Check that dependent floatingip delete operation has completed. if db.check_for_pending_delete_ops_with_parent( session, odl_const.ODL_FLOATINGIP, row.object_uuid): return False # Check that dependent router interface remove operation has completed. if db.check_for_pending_remove_ops_with_parent( session, row.object_uuid): return False return True def validate_floatingip_operation(session, row): """Validate floatingip operation based on dependencies. Validate floating IP operation depending on whether it's dependencies are still in 'pending' or 'processing' state. """ if row.operation in (odl_const.ODL_CREATE, odl_const.ODL_UPDATE): network_id = row.data.get('floating_network_id') if network_id is not None: if not db.check_for_pending_or_processing_ops(session, network_id): port_id = row.data.get('port_id') if port_id is not None: if db.check_for_pending_or_processing_ops(session, port_id): return False else: return False router_id = row.data.get('router_id') if router_id is not None: if db.check_for_pending_or_processing_ops(session, router_id): return False if (row.operation == odl_const.ODL_UPDATE and not _is_valid_update_operation(session, row)): return False elif row.operation == odl_const.ODL_DELETE: # Check for any pending or processing create or update # ops on this uuid itself if db.check_for_pending_or_processing_ops(session, row.object_uuid, [odl_const.ODL_UPDATE, odl_const.ODL_CREATE]): return False return True def validate_router_interface_operation(session, row): """Validate router_interface operation based on dependencies. Validate router_interface operation depending on whether it's dependencies are still in 'pending' or 'processing' state. """ if row.operation == odl_const.ODL_ADD: # Verify that router event has been completed. if db.check_for_pending_or_processing_ops(session, row.data['id']): return False # TODO(rcurran): Check for port_id? if db.check_for_pending_or_processing_ops(session, row.data['subnet_id']): return False elif row.operation == odl_const.ODL_REMOVE: if db.check_for_pending_or_processing_add(session, row.data['id'], row.data['subnet_id']): return False return True def validate_security_group_operation(session, row): """Validate security_group operation based on dependencies. Validate security_group operation depending on whether it's dependencies are still in 'pending' or 'processing' state. e.g. """ return True def validate_security_group_rule_operation(session, row): """Validate security_group_rule operation based on dependencies. Validate security_group_rule operation depending on whether it's dependencies are still in 'pending' or 'processing' state. e.g. """ return True _VALIDATION_MAP = { odl_const.ODL_NETWORK: validate_network_operation, odl_const.ODL_SUBNET: validate_subnet_operation, odl_const.ODL_PORT: validate_port_operation, odl_const.ODL_ROUTER: validate_router_operation, odl_const.ODL_ROUTER_INTF: validate_router_interface_operation, odl_const.ODL_FLOATINGIP: validate_floatingip_operation, odl_const.ODL_SG: validate_security_group_operation, odl_const.ODL_SG_RULE: validate_security_group_rule_operation, } def validate(session, row): """Validate resource dependency in journaled operations. :param session: db session :param row: entry in journal entry to be validated """ return _VALIDATION_MAP[row.object_type](session, row) def register_validator(object_type, validator): """Register validator function for given resource. :param object_type: neutron resource type :param validator: function to be registered which validates resource dependencies """ assert object_type not in _VALIDATION_MAP _VALIDATION_MAP[object_type] = validator