def setup_table(table, table_data, txn, reflist, schema, idl, validator_adapter, errors): # Iterate over each row for index, row_data in table_data.iteritems(): index_values = utils.escaped_split(index) (row, isNew) = setup_row(index_values, table, row_data, txn, reflist, schema, idl, validator_adapter, errors) if row is None: continue op = REQUEST_TYPE_CREATE if isNew else REQUEST_TYPE_UPDATE validator_adapter.add_resource_op(op, row, table) # Save this in global reflist reflist[(table, index)] = (row, isNew)
def index_to_row(index, table_schema, dbtable): """ This subroutine fetches the row reference using index. index is either of type uuid.UUID or is a uri escaped string which contains the combination indices that are used to identify a resource. """ if isinstance(index, uuid.UUID): # index is of type UUID if index in dbtable.rows: return dbtable.rows[index] else: return None else: # index is an escaped combine indices string index_values = utils.escaped_split(index) indexes = table_schema.indexes # if table has no indexes, we create a new entry if not table_schema.index_columns: return None # TODO: Raise an exception here as this is an error if len(index_values) != len(indexes): raise Exception('Combination index error for table') for row in dbtable.rows.itervalues(): i = 0 for index, value in zip(indexes, index_values): if index == 'uuid': if str(row.uuid) != value: break elif str(row.__getattr__(index)) != value: break # matched index i += 1 if i == len(indexes): return row return None
def setup_row(index_values, table, row_data, txn, reflist, schema, idl, validator_adapter, errors, old_row=None): # Initialize the flag for row to check if it is new row is_new = False # Check if row exists in DB if old_row is not None: row = old_row else: row = utils.index_to_row(index_values, schema.ovs_tables[table], idl.tables[table]) # Create a new row if not found in DB if row is None: if table in immutable_tables: # Do NOT add row in Immutable table_data return (None, False) row = txn.insert(idl.tables[table]) is_new = True # Routes are special case - only static routes can be updated if table == 'Route': if not is_new and row.__getattr__('from') != 'static': return (None, False) elif is_new: row.__setattr__('from', 'static') references = schema.ovs_tables[table].references children = schema.ovs_tables[table].children try: request_type = REQUEST_TYPE_CREATE if is_new else REQUEST_TYPE_UPDATE get_all_errors = True # Check for back-references and remove it from the row data since # it will be checked upon recursive call anyways. _row_data = deepcopy(row_data) for data in row_data: if data in children and data not in references: del _row_data[data] results = verify.verify_config_data(_row_data, table, schema, request_type, get_all_errors) except DataValidationFailed as e: errors.extend(e.detail) config_rows = schema.ovs_tables[table].config config_keys = config_rows.keys() # Iterate over all config keys for key in config_keys: # Ignore if row is existing and column is immutable if not is_new and not config_rows[key].mutable: continue # Set the column values from user config if key not in row_data and not is_new: empty_val = utils.get_empty_by_basic_type(row.__getattr__(key)) row.__setattr__(key, empty_val) elif (key in row_data and (is_new or row.__getattr__(key) != row_data[key])): row.__setattr__(key, row_data[key]) # Delete all the keys that don't exist for key in children: child_table = references[key].ref_table \ if key in references else key # Check if table is immutable if child_table in immutable_tables: if not is_new and (key not in row_data or not row_data[key]): # Deep clean-up children, even if missing or empty, # Ignore if immutable if key in references: kv_type = references[key].kv_type if kv_type: rowlist = row.__getattr__(key).values() else: rowlist = row.__getattr__(key) clean_subtree(child_table, rowlist, txn, schema, idl, validator_adapter) else: clean_subtree(child_table, [], txn, schema, idl, validator_adapter, row) continue # forward child references if key in references: table_schema = schema.ovs_tables[table] reference = table_schema.references[key] kv_type = reference.kv_type if not is_new and key not in row_data: if kv_type: row.__setattr__(key, {}) else: row.__setattr__(key, []) else: # back-references if child_table not in row_data: new_data = {} else: new_data = row_data[child_table] remove_deleted_rows(child_table, new_data, txn, schema, idl, validator_adapter, row) # set up children that exist for key in children: child_table = references[key].ref_table \ if key in references else key if key in row_data: if key in references: # forward referenced children table_schema = schema.ovs_tables[table] reference = table_schema.references[key] kv_type = reference.kv_type kv_key_type = None current_child_rows = {} # Key-value type children (Dict type) # Example - BGP_Router is KV-Type child of VRF if kv_type: kv_key_type = reference.kv_key_type if not is_new: current_child_rows = row.__getattr__(key) child_reference_list = {} # Regular children else: child_reference_list = [] # Iterate over each child_row for child_index, child_row_data in row_data[key].iteritems(): current_row = None if kv_type: if (kv_key_type is not None and kv_key_type.name == 'integer'): child_index = int(child_index) if child_index in current_child_rows: current_row = current_child_rows[child_index] child_index_values = [] else: child_index_values = utils.escaped_split(child_index) (child_row, is_child_new) = setup_row(child_index_values, child_table, child_row_data, txn, reflist, schema, idl, validator_adapter, errors, current_row) if child_row is None: continue op = REQUEST_TYPE_CREATE if is_child_new else \ REQUEST_TYPE_UPDATE validator_adapter.add_resource_op(op, child_row, child_table, row, table) if kv_type: child_reference_list.update({child_index: child_row}) else: child_reference_list.append(child_row) # Save this in global reflist reflist[(child_table, child_index)] = (child_row, is_child_new) if child_table not in immutable_tables: row.__setattr__(key, child_reference_list) else: # backward referenced children parent_column = None references = schema.ovs_tables[child_table].references for col_name, col_value in references.iteritems(): if col_value.relation == 'parent': parent_column = col_name break # Iterate over each child_row for child_index, child_row_data in row_data[key].iteritems(): child_index_values = utils.escaped_split(child_index) (child_row, is_child_new) = setup_row(child_index_values, child_table, child_row_data, txn, reflist, schema, idl, validator_adapter, errors) if child_row is None: continue op = REQUEST_TYPE_CREATE if is_child_new else \ REQUEST_TYPE_UPDATE validator_adapter.add_resource_op(op, child_row, child_table, row, table) # Set the references column in child row if parent_column is not None and is_child_new: child_row.__setattr__(parent_column, row) # save this in global reflist reflist[(child_table, child_index)] = (child_row, is_child_new) return (row, is_new)