403Webshell
Server IP : 74.91.139.10  /  Your IP : 10.45.147.122
Web Server : Apache/2.4.67 (Unix)
System : Linux prod-iad-shwpweb1001e 5.14.0-687.26.1.el9_8.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Jul 14 16:32:02 EDT 2026 x86_64
User : FAsyXTyKGY ( 3004)
PHP Version : 8.2.30
Disable Function : passthru,shell_exec,system
MySQL : ON  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /usr/share/oracle-cloud-agent/plugins/osms/osms/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /usr/share/oracle-cloud-agent/plugins/osms/osms/yumutils.py
#   Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
#   Licensed under the Universal Permissive License v 1.0 as shown at https://opensource.org/licenses/UPL.

import logging
import sys
import time
import datetime

from rpm import RPMPROB_FILTER_OLDPACKAGE
from rpm import labelCompare
import yum
import yum.Errors
from yum.plugins import PluginYumExit

sys.path.append("/usr/share/yum-cli")

import callback

sys.path.insert(0, '/usr/share/oracle-cloud-agent/plugins/osms')

from osms import alxutils
from osms import config
from osms import utils
from osms.i18n import sstr


YUM_PID_FILE = '/var/run/yum.pid'
YUM_LOCK_TIMEOUT = 900
YUM_LOCK_INTERVAL = 10
YUM_BASE = None


class YumAction(yum.YumBase):
    def __init__(self):
        yum.YumBase.__init__(self)
        self.cfg = config.initUp2dateConfig()
        self.doConfigSetup(debuglevel=self.cfg["debug"])
        self.cache_only = None

        _do_yum_lock(self)
        self.doTsSetup()
        self.doRpmDBSetup()
        self.doRepoSetup()
        self.doSackSetup()

    # Copied from yum/cli.py, more or less
    def doTransaction(self, p_obj):
        """takes care of package downloading, checking, user confirmation and actually
           RUNNING the transaction"""


        #allow downgrades to support rollbacks
        self.tsInfo.probFilterFlags.append(RPMPROB_FILTER_OLDPACKAGE)

        # Check which packages have to be downloaded
        downloadpkgs = []
        do_erase = False;
        for txmbr in self.tsInfo.getMembers():
            if txmbr.ts_state in ['i', 'u']:
                po = txmbr.po
                if po:
                    downloadpkgs.append(po)
            elif txmbr.ts_state in ['e']:
                do_erase = True;
        #if we're not deleting, we should use the downloadpkgs
        if not do_erase:
            p_obj['packages'] = downloadpkgs

        logging.debug('Downloading Packages:')
        problems = self.downloadPkgs(downloadpkgs)

        if len(problems.keys()) > 0:
            errstring = ''
            errstring += 'Error Downloading Packages:\n'
            for key in problems.keys():
                errors = yum.misc.unique(problems[key])
                for error in errors:
                    errstring += '  %s: %s\n' % (key, error)
            raise yum.Errors.YumBaseError(errstring)

        if self.cfg['retrieveOnly']:
            # We are configured to only download packages (rather than install/update)
            #
            # If all we were asked to do was install/update, skip rest of transaction
            # and return now.
            #
            # If all we were asked to do was remove packages, process the transaction.
            #
            # If we were asked to do a mixture of install/erase - then we can't do a
            # complete transaction, and we have to FAIL, rather than execute or show a
            # success.
            #
            if downloadpkgs and do_erase: # FAIL
                err = 'Mix of install/erase and "retrieveOnly" set - transaction FAILS'
                logging.debug(err)
                raise yum.Errors.YumBaseError(err)
            elif downloadpkgs and not do_erase: # download and exit
                logging.debug('Configured to "retrieveOnly" so skipping package install')
                return 0
            else: # erase-only, continue
                logging.debug('Configured to "retrieveOnly" but only erase-commands - continuing')

        if self.cache_only:
            logging.debug('Just pre-caching packages, skipping package install')
            return 0

        # Check GPG signatures
        if self.gpgsigcheck(downloadpkgs) != 0:
            return 1

        logging.debug('Running Transaction Test')
        tsConf = {}
        for feature in ['diskspacecheck']: # more to come, I'm sure
            tsConf[feature] = getattr(self.conf, feature)

        # clean out the ts b/c we have to give it new paths to the rpms
        del self.ts

        self.initActionTs()
        # save our dsCallback out
        testcb = callback.RPMInstallCallback(output=0)
        testcb.tsInfo = self.tsInfo
        dscb = self.dsCallback
        self.dsCallback = None # dumb, dumb dumb dumb!
        self.populateTs(keepold=0) # sigh
        tserrors = self.ts.test(testcb, conf=tsConf)

        logging.debug('Finished Transaction Test')
        if len(tserrors) > 0:
            errstring = 'Transaction Check Error: '
            for descr in tserrors:
                errstring += '  %s\n' % descr

            raise yum.Errors.YumBaseError(errstring)
        logging.debug('Transaction Test Succeeded')
        del self.ts

        self.initActionTs() # make a new, blank ts to populate
        self.populateTs(keepold=0) # populate the ts
        self.ts.check() #required for ordering
        self.ts.order() # order

        # put back our depcheck callback
        self.dsCallback = dscb

        logging.debug('Running Transaction')
        self.runTransaction(testcb)
        #log the transaction results
        self.log_successful_transaction(p_obj)
        # close things
        return 0

    # Also taken from yum/cli.py
    def gpgsigcheck(self, pkgs):
        '''Perform GPG signature verification on the given packages, installing
        keys if possible

        Returns non-zero if execution should stop (user abort).
        Will raise YumBaseError if there's a problem
        '''
        for po in pkgs:
            result, errmsg = self.sigCheckPkg(po)

            if result == 0:
                # Verified ok, or verify not req'd
                continue

            elif result == 1:
                # bz 433781
                # If the package is a Red Hat pkg, try to install the key and see if it helps
                if self.isRepoUsingRedHatGPG(po):
                    logging.debug("GPG check wasn't successful, will attempt to import key")
                    self.getKeyForPackage(po, askcb=lambda x,y,z: True)
                    logging.debug("GPG key import was good.")
                    # if we got here, the key worked, otherwise an exception is thrown
                else:
                    raise yum.Errors.YumBaseError('Refusing to automatically import keys when running unattended.')
            else:
                # Fatal error
                raise yum.Errors.YumBaseError(errmsg)

        return 0

    def isRepoUsingRedHatGPG(self, po):
        goodValues = ["file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"]
        repo = self.repos.getRepo(po.repoid)
        keyurls = repo.gpgkey
        if len(keyurls) < 1:
            return False
        for keyurl in keyurls:
            if keyurl not in goodValues:
                logging.debug(
                    "keyurl = %s, isn't a known Red Hat key, so this " \
                    "will not be imported.  Manually import this key " \
                    "or set gpgcheck=0 in the OSMS yum plugin configuration file"
                    % (keyurl))
                return False
        return True

    def getInstalledPkgObject(self, package_tup):
        installed = self.rpmdb.returnPackages()

        logging.debug("Searching for installed package to remove: %s"
                      % str(package_tup))
        exactmatch, matched, unmatched = yum.packages.parsePackages(
            installed, (package_tup), casematch=1)
        erases = yum.misc.unique(matched + exactmatch)

        if len(erases) >= 1:
            logging.debug("Found %d package(s) to remove" % len(erases))
            return erases
        else:
            # TODO: we should just fail, I think
            logging.debug("Couldn't find packages to remove")
            return ()

    def check_obsoletes(self, pkgkeys):
        """
        Checks if packages are obsoleted by
        existing packages. If package is obsolete,
        throw yum error.
        """
        nevra_dict = self._nevra_kwarg_parse(pkgkeys)
        pkgs = self.pkgSack.searchNevra(name=nevra_dict['name'],epoch=nevra_dict['epoch'], arch=nevra_dict['arch'], ver=nevra_dict['version'], rel=nevra_dict['release'])

        for po in pkgs:
            obsoleting_pkg = self._test_loop(po, self._pkg2obspkg)
            poprovtup = (po.name, 'EQ', (po.epoch, po.ver, po.release))
            for pkg in self.rpmdb.searchNevra(name=obsoleting_pkg.name):
                if pkg.inPrcoRange('obsoletes', poprovtup):
                    already_obs = pkg

        if already_obs:
            error_string = 'Package %s is obsoleted by %s which is already installed' % (po, already_obs)
            raise yum.Errors.YumBaseError(error_string)

    def log_successful_transaction(self, pkgs):
        """
        Log packages and actions to yum log.
        """
        action_key = pkgs['action']
        actions = {'i': 'Installed', 'u': 'Updated', 'e': 'Erased'}
        try:
            with open(self._getConfig().logfile, 'a') as logfile:
                for pkg in pkgs['packages']:
                    install_time = datetime.datetime.now()
                    log_msg = '{0} OSMS Action - {1}: {2} \n'
                    logfile.write(log_msg.format(install_time.strftime('%b %d %X'), actions[action_key], pkg))
        #We don't want to return an error to the user if logging fails for some reason
        except IOError as err:
            logging.info("Error logging to yum log: {0}".format(err))

    def add_transaction_data(self, transaction_data):
        """ Add packages to transaction.
            transaction_data is in format:
            { 'packages' : [
                [['name', '1.0.0', '1', '', ''], 'e'], ...
                # name,    versio, rel., epoch, arch,   flag
            ]}
            where flag can be:
                i - install
                u - update
                e - remove
                r - rollback
            Note: install and update will check for dependecies and
            obsoletes and will install them if needed.
            Rollback do not check anything and will assume that state
            to which we are rolling back should be correct.
        """
        for pkgtup, action in transaction_data['packages']:
            pkgkeys = {
                'name' : pkgtup[0],
                'epoch' : pkgtup[3],
                'version' : pkgtup[1],
                'release' : pkgtup[2],
            }
            if len(pkgtup) > 4:
                pkgkeys['arch'] = pkgtup[4]
            else:
                pkgtup.append('')
                pkgkeys['arch'] = None
            if action == 'u':
                self.update(**pkgkeys)
            elif action == 'i':
                transaction_len = len(self.install(**pkgkeys))
                # if an empty transaction is returned,
                # this could be due to obsoleted package
                if transaction_len == 0:
                    self.check_obsoletes(pkgkeys)
            elif action == 'r':
                # we are doing rollback, we want exact version
                # no dependecy check
                pkgs = self.pkgSack.searchNevra(name=pkgkeys['name'],
                                                epoch=pkgkeys['epoch'], arch=pkgkeys['arch'],
                                                ver=pkgkeys['version'], rel=pkgkeys['release'])
                if not pkgs:
                    raise yum.Errors.YumBaseError(
                        "Cannot find package %s:%s-%s-%s.%s in any of enabled repositories."
                        % (pkgkeys['epoch'], pkgkeys['name'], pkgkeys['version'], pkgkeys['release'], pkgkeys['arch'])
                    )
                for po in pkgs:
                    self.tsInfo.addInstall(po)
            elif action == 'e':
                package_tup = _yum_package_tup(pkgtup)
                packages = self.getInstalledPkgObject(package_tup)
                for package in packages:
                    self.remove(package)
            else:
                assert False, "Unknown package transaction action."


def get_yum_base():
    global YUM_BASE
    if YUM_BASE is None:
        YUM_BASE = YumAction()
    return YUM_BASE


def _yum_package_tup(package_tup):
    """ Create a yum-style package tuple from an rhn package tuple.
        Allowed styles: n, n.a, n-v-r, n-e:v-r.a, n-v, n-v-r.a,
                        e:n-v-r.a
        Choose from the above styles to be compatible with yum.parsePackage
    """
    n, v, r, e, a = package_tup[:]
    if not e:
        # set epoch to 0 as yum expects
        e = '0'
    if not a:
        pkginfo = '%s-%s-%s' % (n, v, r)
    else:
        pkginfo = '%s-%s:%s-%s.%s' % (n, e, v, r, a)
    return (pkginfo,)


def package_remove(package_list):
    transaction_data = __make_transaction(package_list, 'e')
    return _runTransaction(transaction_data)


def package_update(package_list, cache_only=None):
    yum_base = get_yum_base()
    err = None
    errmsgs = []
    # Remove already installed packages from the list
    for package in package_list[:]:
        pkgkeys = {
            'name' : package[0],
            'epoch' : package[3],
            'version' : package[1],
            'release' : package[2],
        }

        if len(package) == 5 \
            and package[1] == '' \
            and package[2] == '' \
            and package[3] == '' \
            and package[4] == '' \
            and yum_base.rpmdb.searchNevra(name=package[0]):
            logging.debug('Package %s is already installed' % package[0])
            package_list.remove(package)
            continue

        if len(package) > 4:
            pkgkeys['arch'] = package[4]
        else:
            package.append('')
            pkgkeys['arch'] = None

        if pkgkeys['epoch'] == '':
            pkgkeys['epoch'] = None

        pkgs = yum_base.rpmdb.searchNevra(name=pkgkeys['name'], arch=pkgkeys['arch'])
        evr  = yum.packages.PackageEVR(pkgkeys['epoch'], pkgkeys['version'], pkgkeys['release'])

        found = False
        for pkg in pkgs:
            current = pkg.returnEVR()
            currentEVR = (current.epoch, current.version, current.release)
            candidateEVR = (evr.epoch, evr.version, evr.release)
            compare = labelCompare(currentEVR, candidateEVR)
            if compare == 0:
                logging.debug('Package %s already installed' % _yum_package_tup(package))
                package_list.remove(package)
                found = True
                break
            elif compare > 0:
                logging.debug('More recent version of package %s is already installed' % _yum_package_tup(package))
                package_list.remove(package)
                found = True
                break

        if not found:
            available = yum_base.pkgSack.searchNevra(
                name=pkgkeys['name'],
                arch=pkgkeys['arch'],
                epoch=pkgkeys['epoch'],
                ver=pkgkeys['version'],
                rel=pkgkeys['release']
            )
            if not available:
                err = 'Package %s is not available for installation' % _yum_package_tup(package)
                logging.debug('E: %s', err )
                package_list.remove(package)
                errmsgs.append(err)

    # Don't proceed further with empty list,
    # since this would result into an empty yum transaction
    if not package_list:
        if err:
            ret = (32, "Failed: Packages failed to install properly:\n" + '\n'.join(errmsgs),
                   {'version': '1', 'name': "package_install_failure"})
        else:
            ret = (0, "Requested packages already installed", {})
        return ret

    transaction_data = __make_transaction(package_list, 'i')

    return _runTransaction(transaction_data, cache_only)


def __make_transaction(package_list, action):
    """
    Build transaction Data like _runTransaction would expect.
    This is a list of ((n,v,r,e,a), m) where m is either e, i, or u
    """

    transaction_data = {}
    transaction_data['packages'] = []

    #We don't care about this stuff.
    transaction_data['flags'] = []
    transaction_data['vsflags'] = []
    transaction_data['probFilterFlags'] = []

    for package in package_list:
        transaction_data['packages'].append((package, action))

    return transaction_data


class RunTransactionCommand:

    def __init__(self, transaction_data):
        self.transaction_data = transaction_data

    def execute(self, yum_base):
        yum_base.add_transaction_data(self.transaction_data)


def _runTransaction(transaction_data, cache_only=None):
    """ Run a tranaction on a group of packages. """
    command = RunTransactionCommand(transaction_data)
    return _run_yum_action(command, cache_only)


def runTransaction(transaction_data, cache_only=None):
    """ Run a transaction on a group of packages.
        This was historicaly meant as generic call, but
        is only called for rollback.
        Therefore we change all actions "i" (install) to
        "r" (rollback) where we will not check dependencies and obsoletes.
    """
    if cache_only:
        return (0, "no-ops for caching", {})
    for package_object in transaction_data['packages'][:]:
        [package, action] = package_object
        pkgkeys = {
            'name' : package[0],
            'version' : package[1],
            'release' : package[2],
            'epoch' : package[3],
        }

        if len(package) > 4:
            pkgkeys['arch'] = package[4]
        else:
            pkgkeys['arch'] = None
        if pkgkeys['arch'] == '':
            pkgkeys['arch'] = None

        if pkgkeys['epoch'] == '':
            pkgkeys['epoch'] = None

        package_exists = get_yum_base().rpmdb.searchNevra(name=pkgkeys['name'],
                                                          epoch=pkgkeys['epoch'], arch=pkgkeys['arch'],
                                                          ver=pkgkeys['version'], rel=pkgkeys['release'])

        # if we're deleting a package that no longer exists, noop
        if action == 'e' and not package_exists:
            transaction_data['packages'].remove(package_object)
        # if we're installing a package that is already installed, noop
        elif action == 'i' and  package_exists:
            transaction_data['packages'].remove(package_object)

    # Don't proceed further with empty package list,
    # since this would result in an empty yum transaction
    if not transaction_data['packages']:
        return (0, "Requested package actions have already been performed.", {})

    for index, data in enumerate(transaction_data['packages']):
        if data[1] == 'i':
            transaction_data['packages'][index][1] = 'r'
    return _runTransaction(transaction_data)


class FullUpdateCommand:
    def execute(self, yum_base):
        yum_base.update()


def package_full_update( cache_only=None):
    command = FullUpdateCommand()
    return _run_yum_action(command, cache_only)


def _do_yum_lock(yum_base):
    elapsed_time = 0
    while True:
        try:
            return yum_base.doLock(YUM_PID_FILE)
        except Exception as e:
            if 'Existing lock /var/run/yum.pid' not in str(e):
                raise e
            logging.info('Existing lock /var/run/yum.pid: wait for %s seconds, elapsed %s seconds', YUM_LOCK_INTERVAL, elapsed_time)
            time.sleep(YUM_LOCK_INTERVAL)
            elapsed_time += YUM_LOCK_INTERVAL
            if elapsed_time >= YUM_LOCK_TIMEOUT:
                raise e


def _run_yum_action(command, cache_only=None):
    """
    Do something with yum.

    command is an object with an 'execute' method taking yum_base,
    so we can apply different operations to yum_base.
    """

    # TODO: Note to future programmers:
    # When this is running on python 2.5,
    # use the unified try/except/finally
    time_started = time.time()
    try:
        try:
            yum_base = get_yum_base()
            _do_yum_lock(yum_base)
            # Accumulate transaction data
            oldcount = len(yum_base.tsInfo)
            p_list = []
            p_obj = {}
            # build package list for logs
            for package in command.transaction_data['packages']:
                p_list.append(_yum_package_tup(package[0])[0])
                p_obj['action'] = package[1]
            p_obj['packages'] = p_list

            command.execute(yum_base)
            if not len(yum_base.tsInfo) > oldcount:
                raise yum.Errors.YumBaseError('empty transaction')
            # depSolving stage
            (result, resultmsgs) = yum_base.buildTransaction()
            if result == 1:
                # Fatal Error
                for msg in resultmsgs:
                    logging.debug('Error: %s' % msg)
                raise yum.Errors.DepError(resultmsgs)
            elif result == 0 or result == 2:
                # Continue on
                pass
            else:
                # Unknown Error
                for msg in resultmsgs:
                    logging.debug('Error: %s' % msg)
                raise yum.Errors.YumBaseError(resultmsgs)

            logging.debug("Dependencies Resolved")
            yum_base.cache_only=cache_only
            yum_base.doTransaction(p_obj)

            # for sending yum update tid to alx
            if utils.is_alx():
                time_ended = time.time()
                tid = yum_base.history.last().tid
                exit_code = 0
        finally:
            yum_base.closeRpmDB()
            yum_base.doUnlock(YUM_PID_FILE)
    except (yum.Errors.InstallError, yum.Errors.UpdateError) as e:
        message = u"Failed: Packages failed to install properly: %s" % e
        data = {}
        data['version'] = "1"
        data['name'] = "package_install_failure"
        return (32, message, data)
    except yum.Errors.RemoveError as e:
        data = {}
        data['version'] = 0
        data['name'] = "rpmremoveerrors"
        return (15, u"%s" % e, data)
    except yum.Errors.DepError as e:
        message = u"Failed: packages requested raised dependency problems: %s" % e
        data = {}
        data["version"] = "1"
        data["name"] = "failed_deps"
        return (18, message, data)
    except (yum.Errors.YumBaseError, PluginYumExit) as e:
        message = u"Error while executing packages action: %s" % e
        status = 6,
        data = {}
        return (status, message, data)

    # send yum update tid to alx
    if utils.is_alx():
        alxutils.send_yum_updates(alxutils.SUCCESS, exit_code, tid,
                                  time_started, time_ended)
    return (0, "Update Succeeded", {})

Youez - 2016 - github.com/yon3zu
LinuXploit