Ejemplo n.º 1
0
 def __init__(self, op_type, installed=None, erased=None, obsoleted=None,
              reason=SwdbReason.UNKNOWN):
     self.op_type = op_type
     self.installed = installed
     self.erased = erased
     self.obsoleted = list() if obsoleted is None else obsoleted
     self.reason = convert_reason(reason)  # reason for it to be in the transaction set
Ejemplo n.º 2
0
    def beg(self, rpmdb_version, using_pkgs, tsis, cmdline=None):
        tid = self.swdb.trans_beg(
            int(time.time()),
            str(rpmdb_version),
            cmdline or "",
            str(misc.getloginuid()),
            self.releasever)

        self._tid = tid

        for pkg in using_pkgs:
            pid = self.pkg2pid(pkg)
            self.swdb.trans_with(tid, pid)

        if self.group:
            self._log_group_trans(tid)

        for tsi in tsis:
            for (pkg, state, obsoleting) in tsi._history_iterator():
                pid = self.pkg2pid(pkg)
                self.swdb.trans_data_beg(
                    tid,
                    pid,
                    convert_reason(tsi.reason),
                    state,
                    obsoleting)
        return tid
Ejemplo n.º 3
0
 def __init__(self,
              op_type,
              installed=None,
              erased=None,
              obsoleted=None,
              reason=SwdbReason.UNKNOWN):
     self.op_type = op_type
     self.installed = installed
     self.erased = erased
     self.obsoleted = list() if obsoleted is None else obsoleted
     self.reason = convert_reason(
         reason)  # reason for it to be in the transaction set
Ejemplo n.º 4
0
    def beg(self, rpmdb_version, using_pkgs, tsis, cmdline=None):
        tid = self.swdb.trans_beg(int(time.time()),
                                  str(rpmdb_version), cmdline or "",
                                  str(misc.getloginuid()), self.releasever)

        self._tid = tid

        for pkg in using_pkgs:
            pid = self.pkg2pid(pkg)
            self.swdb.trans_with(tid, pid)

        if self.group:
            self._log_group_trans(tid)

        for tsi in tsis:
            for (pkg, state, obsoleting) in tsi._history_iterator():
                pid = self.pkg2pid(pkg)
                self.swdb.trans_data_beg(tid, pid, convert_reason(tsi.reason),
                                         state, obsoleting)
        return tid
Ejemplo n.º 5
0
 def add_install(self, new, obsoleted, reason=SwdbReason.UNKNOWN):
     # :api
     reason = convert_reason(reason)  # support for string reasons
     tsi = TransactionItem(INSTALL, new, obsoleted=obsoleted,
                           reason=reason)
     self._tsis.append(tsi)
Ejemplo n.º 6
0
def get_yumdb_packages(cursor, yumdb_path, repo_fn):
    """ Insert additional data from yumdb info SWDB """

    # prepare pid to pdid dictionary
    cursor.execute("SELECT PD_ID, P_ID FROM PACKAGE_DATA")
    pid_to_pdid = {}
    for row in cursor:
        pid_to_pdid[row[1]] = row[0]

    # load whole yumdb into dictionary structure
    pkgs = {}
    for path, dirs, files in os.walk(yumdb_path):
        if dirs:
            continue
        nvra = path.split('/')[-1].partition('-')[2]
        yumdata = {}
        for yumfile in files:
            with open(os.path.join(path, yumfile)) as f:
                yumdata[yumfile] = f.read()
        pkgs[nvra] = yumdata

    PDSTRINGS = ('from_repo_timestamp',
                 'from_repo_revision',
                 'changed_by',
                 'installed_by')

    # crate PD_ID to T_ID dictionary for further use
    pdid_to_tid = {}
    cursor.execute('SELECT PD_ID, T_ID FROM TRANS_DATA')
    for row in cursor:
        pdid_to_tid[row[0]] = row[1]

    # get all packages from swdb
    cursor.execute('SELECT P_ID, name, version, release, arch FROM PACKAGE')
    allrows = cursor.fetchall()

    # insert data into rows
    for row in allrows:

        # get PDID of the package
        pdid = pid_to_pdid.get(row[0])
        if not pdid:
            continue

        # get package key
        name = '-'.join(row[1:])

        if name in pkgs.keys():
            command = []
            vals = pkgs[name]

            # insert data into PACKAGE_DATA table
            for key in PDSTRINGS:
                temp = vals.get(key)
                if temp:
                    command.append("{}='{}'".format(key, temp))

            # get repository
            temp = vals.get('from_repo')
            if temp:
                repo = repo_fn(cursor, temp)
                command.append("R_ID='{}'".format(repo))

            # Update PACKAGE_DATA row
            if command:
                cmd = "UPDATE PACKAGE_DATA SET {} WHERE PD_ID={}".format(','.join(command), pdid)
                cursor.execute(cmd)

            # resolve reason
            temp = vals.get('reason')
            if temp:
                reason = convert_reason(temp)
                cursor.execute('UPDATE TRANS_DATA SET reason=? WHERE PD_ID=?', (reason, pdid))

            # resolve releasever and command_line
            releasever = vals.get('releasever')
            command_line = vals.get('command_line')
            if releasever or command_line:
                tid = pdid_to_tid.get(pdid)
                if not tid:
                    continue
                # deciding in Python is faster than running both sqlite statements
                if releasever and command_line:
                    cursor.execute('UPDATE TRANS SET cmdline=?, releasever=? WHERE T_ID=?',
                                   (command_line, releasever, tid))
                elif releasever:
                    cursor.execute('UPDATE TRANS SET releasever=? WHERE T_ID=?',
                                   (releasever, tid))
                else:
                    cursor.execute('UPDATE TRANS SET cmdline=? WHERE T_ID=?',
                                   (command_line, tid))
Ejemplo n.º 7
0
def transformSwdb(input_dir, output_file):
    yumdb_path = os.path.join(input_dir, 'yumdb')
    history_path = os.path.join(input_dir, 'history')
    groups_path = os.path.join(input_dir, 'groups.json')

    state_dict = {}
    repo_dict = {}

    # create binding with STATE_TYPE - returns ID
    def bind_state(cursor, desc):
        code = state_dict.get(desc)
        if code:
            return code
        cursor.execute('SELECT state FROM STATE_TYPE WHERE description=?', (desc, ))
        state_id = cursor.fetchone()
        if state_id is None:
            cursor.execute('INSERT INTO STATE_TYPE VALUES(null,?)', (desc, ))
            cursor.execute('SELECT last_insert_rowid()')
            state_id = cursor.fetchone()
        state_dict[desc] = state_id[0]
        return state_id[0]

    # create binding with repo - returns R_ID
    def bind_repo(cursor, name):
        code = repo_dict.get(name)
        if code:
            return code
        cursor.execute('SELECT R_ID FROM REPO WHERE name=?', (name, ))
        rid = cursor.fetchone()
        if rid is None:
            cursor.execute('INSERT INTO REPO VALUES(null,?)', (name, ))
            cursor.execute('SELECT last_insert_rowid()')
            rid = cursor.fetchone()
        repo_dict[name] = rid[0]
        return rid[0]

    # check path to yumdb dir
    if not os.path.isdir(yumdb_path):
        logger.error(_('Error: yumdb directory not valid'))
        return False

    # check path to history dir
    if not os.path.isdir(history_path):
        logger.error(_('Error: history directory not valid'))
        return False

    # check historyDB file and pick newest one
    historydb_file = glob.glob(os.path.join(history_path, "history*"))
    if len(historydb_file) < 1:
        logger.error(_('Error: history database file not valid'))
        return False
    historydb_file.sort()
    historydb_file = historydb_file[0]

    if not os.path.isfile(historydb_file):
        logger.error(_('Error: history database file not valid'))
        return False

    tmp_output_file = output_file + '.transform'
    try:
        # initialise historyDB
        historyDB = sqlite3.connect(historydb_file)
        h_cursor = historyDB.cursor()
    except:
        logger.error(_("ERROR: unable to open the database '{}'").format(historydb_file))
        return False

    try:
        # initialise output DB
        os.rename(output_file, tmp_output_file)
        database = sqlite3.connect(tmp_output_file)
        cursor = database.cursor()
    except:
        logger.error(_("ERROR: unable to create the database '{}'").format(tmp_output_file))
        return False

    # value distribution in tables
    PACKAGE_DATA = ['P_ID', 'R_ID', 'from_repo_revision', 'from_repo_timestamp',
                    'installed_by', 'changed_by']

    TRANS_DATA = ['T_ID', 'PD_ID', 'TG_ID', 'done', 'obsoleting', 'reason', 'state']

    GROUPS = ['name_id', 'name', 'ui_name', 'installed', 'pkg_types']

    ENVIRONMENTS = ['name_id', 'name', 'ui_name', 'pkg_types', 'grp_types']

    logger.info(_("Transforming the software database. It may take some time."))

    # contruction of PACKAGE from pkgtups
    h_cursor.execute('SELECT * FROM pkgtups')
    for row in h_cursor:
        record_P = [
            row[0],  # P_ID
            row[1],  # name
            row[3],  # epoch
            row[4],  # version
            row[5],  # release
            row[2]  # arch
        ]
        if row[6]:
            checksum_type, checksum_data = row[6].split(":", 2)
            record_P.append(checksum_data)
            record_P.append(checksum_type)
        else:
            record_P += ['', '']
        record_P.append(SwdbItem.RPM)  # type
        cursor.execute('INSERT INTO PACKAGE VALUES (?,?,?,?,?,?,?,?,?)', record_P)

    # save changes
    database.commit()

    # construction of PACKAGE_DATA according to pkg_yumdb
    actualPID = 0
    record_PD = [''] * len(PACKAGE_DATA)
    h_cursor.execute('SELECT * FROM pkg_yumdb')

    # for each row in pkg_yumdb
    for row in h_cursor:
        newPID = row[0]
        if actualPID != newPID:
            if actualPID != 0:
                record_PD[0] = actualPID
                # insert new record into PACKAGE_DATA
                PACKAGE_DATA_INSERT(cursor, record_PD)

            actualPID = newPID
            record_PD = [''] * len(PACKAGE_DATA)

        if row[1] in PACKAGE_DATA:
            # collect data for record from pkg_yumdb
            record_PD[PACKAGE_DATA.index(row[1])] = row[2]

        elif row[1] == "from_repo":
            # create binding with REPO table
            record_PD[1] = bind_repo(cursor, row[2])

    record_PD[0] = actualPID
    PACKAGE_DATA_INSERT(cursor, record_PD)  # insert last record

    # save changes
    database.commit()

    # prepare pid to pdid dictionary
    cursor.execute("SELECT PD_ID, P_ID FROM PACKAGE_DATA")
    pid_to_pdid = {}
    for row in cursor:
        pid_to_pdid[row[1]] = row[0]

    obsoleting_pkgs = []

    # trans_data construction
    h_cursor.execute('SELECT tid, pkgtupid, done, state FROM trans_data_pkgs')
    for row in h_cursor:
        state = row[3]
        pid = int(row[1])
        tid = int(row[0])

        # handle Obsoleting packages - save it as separate attribute
        if state == 'Obsoleting':
            obsoleting_pkgs.append((tid, pid))
            continue

        data = [''] * len(TRANS_DATA)
        pdid = pid_to_pdid.get(pid, 0)

        if not pdid:
            # create new entry
            cursor.execute("INSERT INTO PACKAGE_DATA VALUES (null,?,'','','','','')", (pid,))
            cursor.execute('SELECT last_insert_rowid()')
            pdid = cursor.fetchone()[0]
        else:
            # use this entry and delete it from the DB
            del pid_to_pdid[pid]

        # insert trans_data record
        data[TRANS_DATA.index('state')] = bind_state(cursor, state)
        data[TRANS_DATA.index('PD_ID')] = pdid
        data[TRANS_DATA.index('done')] = 1 if row[2] == 'TRUE' else 0
        data[0] = row[0]
        cursor.execute('INSERT INTO TRANS_DATA VALUES (null,?,?,?,?,?,?,?)', data)

    update_cmd = """UPDATE TRANS_DATA SET obsoleting=1 WHERE TD_ID IN (
                        SELECT TD_ID FROM PACKAGE_DATA JOIN TRANS_DATA using (PD_ID)
                            WHERE T_ID=? and P_ID=?)"""

    # set flag for Obsoleting PD_IDs
    for keys in obsoleting_pkgs:
        cursor.execute(update_cmd, keys)

    # save changes
    database.commit()

    trans_cmd = """SELECT tid, trans_beg.timestamp, trans_end.timestamp, trans_beg.rpmdb_version,
                trans_end.rpmdb_version, cmdline, loginuid, null, return_code
                FROM trans_beg join trans_end using(tid) join trans_cmdline using(tid)"""

    # Construction of TRANS
    h_cursor.execute(trans_cmd)
    for row in h_cursor:
        # override empty releasever
        r = list(row)
        del r[7]
        cursor.execute("INSERT INTO TRANS VALUES (?,?,?,?,?,?,?,'',?)", r)

    # get releasever for transactions
    cursor.execute('SELECT T_ID FROM TRANS WHERE releasever=?', ('', ))
    missing = cursor.fetchall()
    for row in missing:
        tid = row[0]
        cmd = "SELECT P_ID FROM TRANS_DATA join PACKAGE_DATA using (PD_ID) WHERE T_ID=? LIMIT 1"
        cursor.execute(cmd, (tid,))
        pids = cursor.fetchall()
        for pid in pids:
            h_cursor.execute("""SELECT yumdb_val FROM pkg_yumdb WHERE pkgtupid=? AND
                             yumdb_key='releasever' LIMIT 1""", pid)
            rlsver = h_cursor.fetchone()
            if rlsver:
                cursor.execute("UPDATE TRANS SET releasever=? WHERE T_ID=?", (rlsver[0], tid))
                break

    # collect reasons
    cursor.execute("""SELECT TD_ID, P_ID FROM TRANS_DATA join PACKAGE_DATA using(PD_ID)
                   join PACKAGE using(P_ID)""")
    missing = cursor.fetchall()
    for row in missing:
        h_cursor.execute("""SELECT yumdb_val FROM pkg_yumdb WHERE pkgtupid=? AND yumdb_key='reason'
                         LIMIT 1""", (row[1],))
        reason = h_cursor.fetchone()
        if reason:
            t_reason = convert_reason(reason[0])
            cursor.execute('UPDATE TRANS_DATA SET reason=? WHERE TD_ID=?', (t_reason, row[0]))

    # fetch additional data from yumdb
    get_yumdb_packages(cursor, yumdb_path, bind_repo)

    # contruction of OUTPUT
    h_cursor.execute('SELECT * FROM trans_script_stdout')
    for row in h_cursor:
        cursor.execute('INSERT INTO OUTPUT VALUES (null,?,?,?)',
                       (row[1], row[2], BIND_OUTPUT(cursor, 'stdout')))

    h_cursor.execute('SELECT * FROM trans_error')
    for row in h_cursor:
        cursor.execute('INSERT INTO OUTPUT VALUES (null,?,?,?)',
                       (row[1], row[2], BIND_OUTPUT(cursor, 'stderr')))

    # construction of GROUPS
    if os.path.isfile(groups_path):
        with open(groups_path) as groups_file:
            data = json.load(groups_file)
            for key in data:
                if key == 'GROUPS':
                    for value in data[key]:
                        record_G = [''] * len(GROUPS)
                        record_G[GROUPS.index('name_id')] = value

                        if 'name' in data[key][value]:
                            record_G[GROUPS.index('name')] = data[key][value]['name']

                        record_G[GROUPS.index('pkg_types')] = data[key][value]['pkg_types']

                        record_G[GROUPS.index('installed')] = True
                        if 'ui_name' in data[key][value]:
                            record_G[GROUPS.index('ui_name')] = data[key][value]['ui_name']

                        cursor.execute('''INSERT INTO GROUPS
                                       VALUES (null,?,?,?,?,?)''',
                                       (record_G))
                        cursor.execute('SELECT last_insert_rowid()')
                        tmp_gid = cursor.fetchone()[0]
                        for package in data[key][value]['full_list']:
                            ADD_GROUPS_PACKAGE(cursor, tmp_gid, package)
                        for package in data[key][value]['pkg_exclude']:
                            ADD_GROUPS_EXCLUDE(cursor, tmp_gid, package)
            for key in data:

                if key == 'ENVIRONMENTS':
                    for value in data[key]:
                        record_E = [''] * len(ENVIRONMENTS)
                        record_E[GROUPS.index('name_id')] = value
                        if 'name' in data[key][value]:
                            record_G[GROUPS.index('name')] = data[key][value]['name']
                        record_E[ENVIRONMENTS.index('grp_types')] = data[key][value]['grp_types']
                        record_E[ENVIRONMENTS.index('pkg_types')] = data[key][value]['pkg_types']
                        if 'ui_name' in data[key][value]:
                            record_E[ENVIRONMENTS.index('ui_name')] = data[key][value]['ui_name']

                        cursor.execute('''INSERT INTO ENVIRONMENTS
                                       VALUES (null,?,?,?,?,?)''',
                                       (record_E))
                        cursor.execute('SELECT last_insert_rowid()')
                        tmp_eid = cursor.fetchone()[0]

                        for package in data[key][value]['full_list']:
                            BIND_ENV_GROUP(cursor, tmp_eid, package)
                        for package in data[key][value]['pkg_exclude']:
                            ADD_ENV_EXCLUDE(cursor, tmp_eid, package)

    # construction of TRANS_GROUP_DATA from GROUPS
    cursor.execute('SELECT * FROM GROUPS')
    tmp_groups = cursor.fetchall()
    for row in tmp_groups:
        command = []
        for pattern in row[1:4]:
            if pattern:
                command.append("cmdline LIKE '%{}%'".format(pattern))
        if command:
            cursor.execute("SELECT T_ID FROM TRANS WHERE " + " or ".join(command))
            tmp_trans = cursor.fetchall()
            if tmp_trans:
                for single_trans in tmp_trans:
                    data = (single_trans[0], row[0], row[1], row[2], row[3], row[4], row[5])
                    cursor.execute("INSERT INTO TRANS_GROUP_DATA VALUES(null,?,?,?,?,?,?,?)", data)

    # construction of TRANS_GROUP_DATA from ENVIRONMENTS
    cursor.execute('SELECT * FROM ENVIRONMENTS WHERE ui_name!=?', ('', ))
    tmp_env = cursor.fetchall()
    for row in tmp_env:
        command = []
        for pattern in row[1:4]:
            if pattern:
                command.append("cmdline LIKE '%{}%'".format(pattern))
        if command:
            cursor.execute("SELECT T_ID FROM TRANS WHERE " + " or ".join(command))
            tmp_trans = cursor.fetchall()
            if tmp_trans:
                for trans in tmp_trans:
                    cursor.execute("SELECT G_ID FROM ENVIRONMENTS_GROUPS WHERE E_ID=?", (row[0],))
                    tmp_groups = cursor.fetchall()
                    for gid in tmp_groups:
                        cursor.execute("SELECT * FROM GROUPS WHERE G_ID=?", (gid[0],))
                        data = cursor.fetchone()
                        tgdata = (trans[0], data[0], data[1], data[2], data[3], data[4], data[5])
                        cursor.execute("INSERT INTO TRANS_GROUP_DATA VALUES(null,?,?,?,?,?,?,?)",
                                       tgdata)

    # create Transaction performed with package
    h_cursor.execute('SELECT tid, pkgtupid FROM trans_with_pkgs')
    for row in h_cursor:
        cursor.execute('INSERT INTO TRANS_WITH VALUES (null,?,?)', row)

    # save changes
    database.commit()

    # close connection
    database.close()
    historyDB.close()

    # successful
    os.rename(tmp_output_file, output_file)

    return True
Ejemplo n.º 8
0
def get_yumdb_packages(cursor, yumdb_path, repo_fn):
    """ Insert additional data from yumdb info SWDB """

    # prepare pid to pdid dictionary
    cursor.execute("SELECT PD_ID, P_ID FROM PACKAGE_DATA")
    pid_to_pdid = {}
    for row in cursor:
        pid_to_pdid[row[1]] = row[0]

    # load whole yumdb into dictionary structure
    pkgs = {}
    for path, dirs, files in os.walk(yumdb_path):
        if dirs:
            continue
        nvra = path.split('/')[-1].partition('-')[2]
        yumdata = {}
        for yumfile in files:
            with open(os.path.join(path, yumfile)) as f:
                yumdata[yumfile] = f.read()
        pkgs[nvra] = yumdata

    PDSTRINGS = ('from_repo_timestamp', 'from_repo_revision', 'changed_by',
                 'installed_by')

    # crate PD_ID to T_ID dictionary for further use
    pdid_to_tid = {}
    cursor.execute('SELECT PD_ID, T_ID FROM TRANS_DATA')
    for row in cursor:
        pdid_to_tid[row[0]] = row[1]

    # get all packages from swdb
    cursor.execute('SELECT P_ID, name, version, release, arch FROM PACKAGE')
    allrows = cursor.fetchall()

    # insert data into rows
    for row in allrows:

        # get PDID of the package
        pdid = pid_to_pdid.get(row[0])
        if not pdid:
            continue

        # get package key
        name = '-'.join(row[1:])

        if name in pkgs.keys():
            command = []
            vals = pkgs[name]

            # insert data into PACKAGE_DATA table
            for key in PDSTRINGS:
                temp = vals.get(key)
                if temp:
                    command.append("{}='{}'".format(key, temp))

            # get repository
            temp = vals.get('from_repo')
            if temp:
                repo = repo_fn(cursor, temp)
                command.append("R_ID='{}'".format(repo))

            # Update PACKAGE_DATA row
            if command:
                cmd = "UPDATE PACKAGE_DATA SET {} WHERE PD_ID={}".format(
                    ','.join(command), pdid)
                cursor.execute(cmd)

            # resolve reason
            temp = vals.get('reason')
            if temp:
                reason = convert_reason(temp)
                cursor.execute('UPDATE TRANS_DATA SET reason=? WHERE PD_ID=?',
                               (reason, pdid))

            # resolve releasever and command_line
            releasever = vals.get('releasever')
            command_line = vals.get('command_line')
            if releasever or command_line:
                tid = pdid_to_tid.get(pdid)
                if not tid:
                    continue
                # deciding in Python is faster than running both sqlite statements
                if releasever and command_line:
                    cursor.execute(
                        'UPDATE TRANS SET cmdline=?, releasever=? WHERE T_ID=?',
                        (command_line, releasever, tid))
                elif releasever:
                    cursor.execute(
                        'UPDATE TRANS SET releasever=? WHERE T_ID=?',
                        (releasever, tid))
                else:
                    cursor.execute('UPDATE TRANS SET cmdline=? WHERE T_ID=?',
                                   (command_line, tid))
Ejemplo n.º 9
0
def transformSwdb(input_dir, output_file):
    yumdb_path = os.path.join(input_dir, 'yumdb')
    history_path = os.path.join(input_dir, 'history')
    groups_path = os.path.join(input_dir, 'groups.json')

    state_dict = {}
    repo_dict = {}

    # create binding with STATE_TYPE - returns ID
    def bind_state(cursor, desc):
        code = state_dict.get(desc)
        if code:
            return code
        cursor.execute('SELECT state FROM STATE_TYPE WHERE description=?',
                       (desc, ))
        state_id = cursor.fetchone()
        if state_id is None:
            cursor.execute('INSERT INTO STATE_TYPE VALUES(null,?)', (desc, ))
            cursor.execute('SELECT last_insert_rowid()')
            state_id = cursor.fetchone()
        state_dict[desc] = state_id[0]
        return state_id[0]

    # create binding with repo - returns R_ID
    def bind_repo(cursor, name):
        code = repo_dict.get(name)
        if code:
            return code
        cursor.execute('SELECT R_ID FROM REPO WHERE name=?', (name, ))
        rid = cursor.fetchone()
        if rid is None:
            cursor.execute('INSERT INTO REPO VALUES(null,?)', (name, ))
            cursor.execute('SELECT last_insert_rowid()')
            rid = cursor.fetchone()
        repo_dict[name] = rid[0]
        return rid[0]

    # check path to yumdb dir
    if not os.path.isdir(yumdb_path):
        logger.error(_('Error: yumdb directory not valid'))
        return False

    # check path to history dir
    if not os.path.isdir(history_path):
        logger.error(_('Error: history directory not valid'))
        return False

    # check historyDB file and pick newest one
    historydb_file = glob.glob(os.path.join(history_path, "history*"))
    if len(historydb_file) < 1:
        logger.error(_('Error: history database file not valid'))
        return False
    historydb_file.sort()
    historydb_file = historydb_file[0]

    if not os.path.isfile(historydb_file):
        logger.error(_('Error: history database file not valid'))
        return False

    tmp_output_file = output_file + '.transform'
    try:
        # initialise historyDB
        historyDB = sqlite3.connect(historydb_file)
        h_cursor = historyDB.cursor()
    except:
        logger.error(
            _("ERROR: unable to open the database '{}'").format(
                historydb_file))
        return False

    try:
        # initialise output DB
        os.rename(output_file, tmp_output_file)
        database = sqlite3.connect(tmp_output_file)
        cursor = database.cursor()
    except:
        logger.error(
            _("ERROR: unable to create the database '{}'").format(
                tmp_output_file))
        return False

    # value distribution in tables
    PACKAGE_DATA = [
        'P_ID', 'R_ID', 'from_repo_revision', 'from_repo_timestamp',
        'installed_by', 'changed_by'
    ]

    TRANS_DATA = [
        'T_ID', 'PD_ID', 'TG_ID', 'done', 'obsoleting', 'reason', 'state'
    ]

    GROUPS = ['name_id', 'name', 'ui_name', 'installed', 'pkg_types']

    ENVIRONMENTS = ['name_id', 'name', 'ui_name', 'pkg_types', 'grp_types']

    logger.info(
        _("Transforming the software database. It may take some time."))

    # contruction of PACKAGE from pkgtups
    h_cursor.execute('SELECT * FROM pkgtups')
    for row in h_cursor:
        record_P = [
            row[0],  # P_ID
            row[1],  # name
            row[3],  # epoch
            row[4],  # version
            row[5],  # release
            row[2]  # arch
        ]
        if row[6]:
            checksum_type, checksum_data = row[6].split(":", 2)
            record_P.append(checksum_data)
            record_P.append(checksum_type)
        else:
            record_P += ['', '']
        record_P.append(SwdbItem.RPM)  # type
        cursor.execute('INSERT INTO PACKAGE VALUES (?,?,?,?,?,?,?,?,?)',
                       record_P)

    # save changes
    database.commit()

    # construction of PACKAGE_DATA according to pkg_yumdb
    actualPID = 0
    record_PD = [''] * len(PACKAGE_DATA)
    h_cursor.execute('SELECT * FROM pkg_yumdb')

    # for each row in pkg_yumdb
    for row in h_cursor:
        newPID = row[0]
        if actualPID != newPID:
            if actualPID != 0:
                record_PD[0] = actualPID
                # insert new record into PACKAGE_DATA
                PACKAGE_DATA_INSERT(cursor, record_PD)

            actualPID = newPID
            record_PD = [''] * len(PACKAGE_DATA)

        if row[1] in PACKAGE_DATA:
            # collect data for record from pkg_yumdb
            record_PD[PACKAGE_DATA.index(row[1])] = row[2]

        elif row[1] == "from_repo":
            # create binding with REPO table
            record_PD[1] = bind_repo(cursor, row[2])

    record_PD[0] = actualPID
    PACKAGE_DATA_INSERT(cursor, record_PD)  # insert last record

    # save changes
    database.commit()

    # prepare pid to pdid dictionary
    cursor.execute("SELECT PD_ID, P_ID FROM PACKAGE_DATA")
    pid_to_pdid = {}
    for row in cursor:
        pid_to_pdid[row[1]] = row[0]

    obsoleting_pkgs = []

    # trans_data construction
    h_cursor.execute('SELECT tid, pkgtupid, done, state FROM trans_data_pkgs')
    for row in h_cursor:
        state = row[3]
        pid = int(row[1])
        tid = int(row[0])

        # handle Obsoleting packages - save it as separate attribute
        if state == 'Obsoleting':
            obsoleting_pkgs.append((tid, pid))
            continue

        data = [''] * len(TRANS_DATA)
        pdid = pid_to_pdid.get(pid, 0)

        if not pdid:
            # create new entry
            cursor.execute(
                "INSERT INTO PACKAGE_DATA VALUES (null,?,'','','','','')",
                (pid, ))
            cursor.execute('SELECT last_insert_rowid()')
            pdid = cursor.fetchone()[0]
        else:
            # use this entry and delete it from the DB
            del pid_to_pdid[pid]

        # insert trans_data record
        data[TRANS_DATA.index('state')] = bind_state(cursor, state)
        data[TRANS_DATA.index('PD_ID')] = pdid
        data[TRANS_DATA.index('done')] = 1 if row[2] == 'TRUE' else 0
        data[0] = row[0]
        cursor.execute('INSERT INTO TRANS_DATA VALUES (null,?,?,?,?,?,?,?)',
                       data)

    update_cmd = """UPDATE TRANS_DATA SET obsoleting=1 WHERE TD_ID IN (
                        SELECT TD_ID FROM PACKAGE_DATA JOIN TRANS_DATA using (PD_ID)
                            WHERE T_ID=? and P_ID=?)"""

    # set flag for Obsoleting PD_IDs
    for keys in obsoleting_pkgs:
        cursor.execute(update_cmd, keys)

    # save changes
    database.commit()

    trans_cmd = """SELECT tid, trans_beg.timestamp, trans_end.timestamp, trans_beg.rpmdb_version,
                trans_end.rpmdb_version, cmdline, loginuid, null, return_code
                FROM trans_beg join trans_end using(tid) join trans_cmdline using(tid)"""

    # Construction of TRANS
    h_cursor.execute(trans_cmd)
    for row in h_cursor:
        # override empty releasever
        r = list(row)
        del r[7]
        cursor.execute("INSERT INTO TRANS VALUES (?,?,?,?,?,?,?,'',?)", r)

    # get releasever for transactions
    cursor.execute('SELECT T_ID FROM TRANS WHERE releasever=?', ('', ))
    missing = cursor.fetchall()
    for row in missing:
        tid = row[0]
        cmd = "SELECT P_ID FROM TRANS_DATA join PACKAGE_DATA using (PD_ID) WHERE T_ID=? LIMIT 1"
        cursor.execute(cmd, (tid, ))
        pids = cursor.fetchall()
        for pid in pids:
            h_cursor.execute(
                """SELECT yumdb_val FROM pkg_yumdb WHERE pkgtupid=? AND
                             yumdb_key='releasever' LIMIT 1""", pid)
            rlsver = h_cursor.fetchone()
            if rlsver:
                cursor.execute("UPDATE TRANS SET releasever=? WHERE T_ID=?",
                               (rlsver[0], tid))
                break

    # collect reasons
    cursor.execute(
        """SELECT TD_ID, P_ID FROM TRANS_DATA join PACKAGE_DATA using(PD_ID)
                   join PACKAGE using(P_ID)""")
    missing = cursor.fetchall()
    for row in missing:
        h_cursor.execute(
            """SELECT yumdb_val FROM pkg_yumdb WHERE pkgtupid=? AND yumdb_key='reason'
                         LIMIT 1""", (row[1], ))
        reason = h_cursor.fetchone()
        if reason:
            t_reason = convert_reason(reason[0])
            cursor.execute('UPDATE TRANS_DATA SET reason=? WHERE TD_ID=?',
                           (t_reason, row[0]))

    # fetch additional data from yumdb
    get_yumdb_packages(cursor, yumdb_path, bind_repo)

    # contruction of OUTPUT
    h_cursor.execute('SELECT * FROM trans_script_stdout')
    for row in h_cursor:
        cursor.execute('INSERT INTO OUTPUT VALUES (null,?,?,?)',
                       (row[1], row[2], BIND_OUTPUT(cursor, 'stdout')))

    h_cursor.execute('SELECT * FROM trans_error')
    for row in h_cursor:
        cursor.execute('INSERT INTO OUTPUT VALUES (null,?,?,?)',
                       (row[1], row[2], BIND_OUTPUT(cursor, 'stderr')))

    # construction of GROUPS
    if os.path.isfile(groups_path):
        with open(groups_path) as groups_file:
            data = json.load(groups_file)
            for key in data:
                if key == 'GROUPS':
                    for value in data[key]:
                        record_G = [''] * len(GROUPS)
                        record_G[GROUPS.index('name_id')] = value

                        if 'name' in data[key][value]:
                            record_G[GROUPS.index(
                                'name')] = data[key][value]['name']

                        record_G[GROUPS.index(
                            'pkg_types')] = data[key][value]['pkg_types']

                        record_G[GROUPS.index('installed')] = True
                        if 'ui_name' in data[key][value]:
                            record_G[GROUPS.index(
                                'ui_name')] = data[key][value]['ui_name']

                        cursor.execute(
                            '''INSERT INTO GROUPS
                                       VALUES (null,?,?,?,?,?)''', (record_G))
                        cursor.execute('SELECT last_insert_rowid()')
                        tmp_gid = cursor.fetchone()[0]
                        for package in data[key][value]['full_list']:
                            ADD_GROUPS_PACKAGE(cursor, tmp_gid, package)
                        for package in data[key][value]['pkg_exclude']:
                            ADD_GROUPS_EXCLUDE(cursor, tmp_gid, package)
            for key in data:

                if key == 'ENVIRONMENTS':
                    for value in data[key]:
                        record_E = [''] * len(ENVIRONMENTS)
                        record_E[GROUPS.index('name_id')] = value
                        if 'name' in data[key][value]:
                            record_G[GROUPS.index(
                                'name')] = data[key][value]['name']
                        record_E[ENVIRONMENTS.index(
                            'grp_types')] = data[key][value]['grp_types']
                        record_E[ENVIRONMENTS.index(
                            'pkg_types')] = data[key][value]['pkg_types']
                        if 'ui_name' in data[key][value]:
                            record_E[ENVIRONMENTS.index(
                                'ui_name')] = data[key][value]['ui_name']

                        cursor.execute(
                            '''INSERT INTO ENVIRONMENTS
                                       VALUES (null,?,?,?,?,?)''', (record_E))
                        cursor.execute('SELECT last_insert_rowid()')
                        tmp_eid = cursor.fetchone()[0]

                        for package in data[key][value]['full_list']:
                            BIND_ENV_GROUP(cursor, tmp_eid, package)
                        for package in data[key][value]['pkg_exclude']:
                            ADD_ENV_EXCLUDE(cursor, tmp_eid, package)

    # construction of TRANS_GROUP_DATA from GROUPS
    cursor.execute('SELECT * FROM GROUPS')
    tmp_groups = cursor.fetchall()
    for row in tmp_groups:
        command = []
        for pattern in row[1:4]:
            if pattern:
                command.append("cmdline LIKE '%{}%'".format(pattern))
        if command:
            cursor.execute("SELECT T_ID FROM TRANS WHERE " +
                           " or ".join(command))
            tmp_trans = cursor.fetchall()
            if tmp_trans:
                for single_trans in tmp_trans:
                    data = (single_trans[0], row[0], row[1], row[2], row[3],
                            row[4], row[5])
                    cursor.execute(
                        "INSERT INTO TRANS_GROUP_DATA VALUES(null,?,?,?,?,?,?,?)",
                        data)

    # construction of TRANS_GROUP_DATA from ENVIRONMENTS
    cursor.execute('SELECT * FROM ENVIRONMENTS WHERE ui_name!=?', ('', ))
    tmp_env = cursor.fetchall()
    for row in tmp_env:
        command = []
        for pattern in row[1:4]:
            if pattern:
                command.append("cmdline LIKE '%{}%'".format(pattern))
        if command:
            cursor.execute("SELECT T_ID FROM TRANS WHERE " +
                           " or ".join(command))
            tmp_trans = cursor.fetchall()
            if tmp_trans:
                for trans in tmp_trans:
                    cursor.execute(
                        "SELECT G_ID FROM ENVIRONMENTS_GROUPS WHERE E_ID=?",
                        (row[0], ))
                    tmp_groups = cursor.fetchall()
                    for gid in tmp_groups:
                        cursor.execute("SELECT * FROM GROUPS WHERE G_ID=?",
                                       (gid[0], ))
                        data = cursor.fetchone()
                        tgdata = (trans[0], data[0], data[1], data[2], data[3],
                                  data[4], data[5])
                        cursor.execute(
                            "INSERT INTO TRANS_GROUP_DATA VALUES(null,?,?,?,?,?,?,?)",
                            tgdata)

    # create Transaction performed with package
    h_cursor.execute('SELECT tid, pkgtupid FROM trans_with_pkgs')
    for row in h_cursor:
        cursor.execute('INSERT INTO TRANS_WITH VALUES (null,?,?)', row)

    # save changes
    database.commit()

    # close connection
    database.close()
    historyDB.close()

    # successful
    os.rename(tmp_output_file, output_file)

    return True
Ejemplo n.º 10
0
 def add_install(self, new, obsoleted, reason=SwdbReason.UNKNOWN):
     # :api
     reason = convert_reason(reason)  # support for string reasons
     tsi = TransactionItem(INSTALL, new, obsoleted=obsoleted, reason=reason)
     self._tsis.append(tsi)