def clean_row(table, row, txn, schema, idl, validator_adapter):
    references = schema.ovs_tables[table].references
    children = schema.ovs_tables[table].children
    config_rows = schema.ovs_tables[table].config

    # Clean children
    for key in children:
        if key in references:
            kv_type = references[key].kv_type
            child_table = references[key].ref_table
            if child_table not in immutable_tables:
                if kv_type:
                    row.__setattr__(key, {})
                else:
                    row.__setattr__(key, [])
            else:
                if kv_type:
                    rowlist = row.__getattr__(key).values()
                else:
                    rowlist = row.__getattr__(key)
                clean_subtree(child_table, rowlist, txn, schema, idl,
                              validator_adapter)
        else:
            child_table = key
            clean_subtree(child_table, [], txn, schema, idl,
                          validator_adapter, row)

    # Clean config fields
    for key in config_rows.keys():
        if not config_rows[key].mutable:
            continue
        empty_val = utils.get_empty_by_basic_type(row.__getattr__(key))
        row.__setattr__(key, empty_val)

    # Clean references
    for key, val in references.iteritems():
        if val.relation == 'reference' and val.mutable:
            row.__setattr__(key, [])
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)
Exemple #3
0
def setup_row(rowdata, table_name, schema, idl, txn):
    """
    set up rows recursively
    """
    row_index = rowdata.keys()[0]
    row_data = rowdata.values()[0]
    table_schema = schema.ovs_tables[table_name]
    idl_table = idl.tables[table_name]

    # get row reference from table
    _new = False
    row = index_to_row(row_index, table_schema, idl_table)
    if row is None:
        row = txn.insert(idl.tables[table_name])
        _new = True

    # NOTE: populate configuration data
    config_keys = table_schema.config.keys()
    for key in config_keys:

        # TODO: return error if trying to set an immutable column
        # skip if trying to set an immutable column for an existing row
        if not _new and table_schema.config[key].mutable is False:
            continue

        if key not in row_data:
            # skip if it's a new row
            if _new or row.__getattr__(key) is None:
                continue
            else:
                # set the right empty value
                value =  utils.get_empty_by_basic_type(row.__getattr__(key))
        else:
            value = row_data[key]

        row.__setattr__(key, value)

    # NOTE: populate non-config index columns
    if _new:
        for key in table_schema.indexes:
            if key is 'uuid':
                continue

            if key not in table_schema.config.keys():
                row.__setattr__(key, row_data[key])

    # NOTE: set up child references
    for key in table_schema.children:

        # NOTE: 'forward' type children
        if key in table_schema.references:

            child_table_name = table_schema.references[key].ref_table

            # skip immutable column
            if not _new and not table_schema.references[key].mutable:
                continue

            # set up empty reference list
            if key not in row_data:
                if _new or row.__getattr__(key) is None:
                    continue
                else:
                   value = utils.get_empty_by_basic_type(row.__getattr__(key))
                row.__setattr__(key, value)

            else:
                new_data = row_data[key]

                # {key:UUID} type of reference check
                kv_type = table_schema.references[key].kv_type

                # if not a new row, delete non-existent child references
                if not _new:
                    current_list = row.__getattr__(key)
                    if current_list:
                        if kv_type:
                            current_list = current_list.values()
                        delete_list = []
                        for item in current_list:
                            index = utils.row_to_index(item, child_table_name, schema, idl)
                            if index not in new_data:
                                delete_list.append(item)

                        if delete_list:
                            for item in delete_list:
                                _delete(item, child_table_name, schema, idl, txn)

                # setup children
                children = {}
                for index, child_data in new_data.iteritems():
                    _child = setup_row({index:child_data}, child_table_name, schema, idl, txn)
                    children.update(_child)

                # NOTE: If the child table doesn't have indexes, replace json index
                # with row.uuid
                if not schema.ovs_tables[child_table_name].index_columns:
                    for k,v in children.iteritems():
                        new_data[v.uuid] = new_data[k]
                        del new_data[k]

                if kv_type:
                    if table_schema.references[key].kv_key_type.name == 'integer':
                        tmp = {}
                        for k,v in children.iteritems():
                            tmp[int(k)] = v
                        children = tmp
                    row.__setattr__(key, children)
                else:
                    row.__setattr__(key, children.values())

        # Backward reference
        else:

            # get list of all 'backward' references
            column_name = None
            for x, y in schema.ovs_tables[key].references.iteritems():
                if y.relation == OVSDB_SCHEMA_PARENT:
                    column_name = x
                    break

            # delete non-existent rows

            # get list of all rows with same parent
            if not _new:
                current_list = []
                for item in idl.tables[key].rows.itervalues():
                    parent = item.__getattr__(column_name)
                    if parent.uuid == row.uuid:
                        current_list.append(item)

                new_data = None
                if key in row_data:
                    new_data = row_data[key]

                if current_list:
                    delete_list = []
                    if new_data is None:
                        delete_list = current_list
                    else:
                        for item in current_list:
                            index = utils.row_to_index(item,key, schema, idl)
                            if index not in new_data:
                                delete_list.append(item)

                    if delete_list:
                        _delete(delete_list, key, schema, idl, txn)

                # set up children rows
                if new_data is not None:
                    for x,y in new_data.iteritems():
                        child = setup_row({x:y}, key, schema, idl, txn)

                        # fill the parent reference column
                        child.values()[0].__setattr__(column_name, row)

    return {row_index:row}