def _addYumRepo(self, name, baseurl, mirrorlist=None, proxyurl=None, **kwargs): """ Add a yum repo to the YumBase instance. """ from yum.Errors import RepoError # First, delete any pre-existing repo with the same name. with _yum_lock: if name in self._yum.repos.repos: self._yum.repos.delete(name) logger.debug("adding yum repo %s with baseurl %s and mirrorlist %s" % (name, baseurl, mirrorlist)) with _yum_lock: # Then add it to yum's internal structures. obj = self._yum.add_enable_repo(name, baseurl=[baseurl], mirrorlist=mirrorlist, **kwargs) # this will trigger retrieval of repomd.xml, which is small and yet # gives us some assurance that the repo config is sane # YUMFIXME: yum's instant policy doesn't work as advertised obj.mdpolicy = "meh" try: obj.repoXML except RepoError as e: raise Exception('MetadataError', 'name: %s baseurl:%s err: %s' % (name, baseurl, e.value)) # Adding a new repo means the cached packages and groups lists # are out of date. Clear them out now so the next reference to # either will cause it to be regenerated. self._groups = None self._packages = []
def _deselectYumGroup(self, groupid): # deselect the group in comps logger.debug("deselect group %s" % groupid) with _yum_lock: try: self._yum.deselectGroup(groupid, force=True) except yum.Errors.GroupsError: raise NoSuchGroup(groupid)
def disableRepo(self, repo_id): """ Disable a repo as specified by id. """ logger.debug("disabling repo %s" % repo_id) if repo_id in self.repos: self._yum.repos.disableRepo(repo_id) self._groups = None self._packages = []
def _deselectYumPackage(self, pkgid): """Mark a package to be excluded from installation. pkgid - The name of a package to be excluded. This could include a version or architecture component. """ logger.debug("deselect package %s" % pkgid) with _yum_lock: self._yum.tsInfo.deselect(pkgid)
def release(self): from yum.packageSack import MetaSack with _yum_lock: logger.debug("deleting package sacks") if hasattr(self._yum, "_pkgSack"): self._yum._pkgSack = None self._yum.repos.pkgSack = MetaSack() for repo in self._yum.repos.repos.values(): repo._sack = None
def addRepo(self, repo): """ Add a custom repo. """ logger.debug("adding new repo %s" % repo.name) self._addYumRepo(repo.name, repo.baseurl, repo.mirrorlist, cost=repo.cost, exclude=repo.excludepkgs, includepkgs=repo.includepkgs, proxyurl=repo.proxy, sslverify=repo.sslverify)
def _selectYumPackage(self, pkgid): """Mark a package for installation. pkgid - The name of a package to be installed. This could include a version or architecture component. """ logger.debug("select package %s" % pkgid) with _yum_lock: try: mbrs = self._yum.install(pattern=pkgid) except yum.Errors.InstallError: raise NoSuchPackage(pkgid)
def removeRepo(self, repo_id): """ Remove a repo as specified by id. """ logger.debug("removing repo %s" % repo_id) # if this is an NFS repo, we'll want to unmount the NFS mount after # removing the repo mountpoint = None yum_repo = self._yum.repos.getRepo(repo_id) ks_repo = self.getRepo(repo_id) if yum_repo and ks_repo and ks_repo.baseurl.startswith("nfs:"): mountpoint = yum_repo.baseurl[0][7:] # strip leading "file://" self._removeYumRepo(repo_id)
def _selectYumGroup(self, groupid, default=True, optional=False): # select the group in comps pkg_types = ['mandatory'] if default: pkg_types.append("default") if optional: pkg_types.append("optional") logger.debug("select group %s" % groupid) with _yum_lock: try: self._yum.selectGroup(groupid, group_package_types=pkg_types) except yum.Errors.GroupsError: raise NoSuchGroup(groupid)
def checkSoftwareSelection(self): logger.info("checking software selection") self.txID = time.time() self.release() with _yum_lock: self._yum._undoDepInstalls() self._applyYumSelections() with _yum_lock: # doPostSelection # select kernel packages # select packages needed for storage, bootloader # check dependencies logger.info("checking dependencies") (code, msgs) = self._yum.buildTransaction( unfinished_transactions_check=False) self._removeTxSaveFile() if code == 0: # empty transaction? logger.debug("empty transaction") elif code == 2: # success logger.debug("success") # elif self.data.packages.handleMissing == KS_MISSING_IGNORE: # logger.debug("ignoring missing due to ks config") # elif self.data.upgrade.upgrade: # logger.debug("ignoring unresolved deps on upgrade") else: for msg in msgs: logger.warning(msg) raise DependencyError(msgs) self.calculateSpaceNeeds() logger.info("%d packages selected totalling %s" % (len(self._yum.tsInfo.getMembers()), self.spaceRequired))
def _writeInstallConfig(self): """ Write out the yum config that will be used to install packages. Write out repo config files for all enabled repos, then create a new YumBase instance with the new filesystem tree as its install root. """ self._repos_dir = "/tmp/yum.repos.d" if not os.path.isdir(self._repos_dir): os.mkdir(self._repos_dir) for repo in self._yum.repos.listEnabled(): cfg_path = "%s/%s.repo" % (self._repos_dir, repo.id) #ks_repo = self.getRepo(repo.id) with open(cfg_path, "w") as f: f.write("[%s]\n" % repo.id) f.write("name=Install - %s\n" % repo.id) f.write("enabled=1\n") if repo.mirrorlist: f.write("mirrorlist=%s" % repo.mirrorlist) elif repo.baseurl: f.write("baseurl=%s\n" % repo.baseurl[0]) else: logger.error("repo %s has no baseurl or mirrorlist" % repo.id) f.close() os.unlink(cfg_path) continue releasever = self._yum.conf.yumvar['releasever'] self._writeYumConfig() self._resetYum(root=CF.D.TGTSYS_ROOT, keep_cache=True) logger.debug("setting releasever to previous value of %s" % releasever) self._yum.preconf.releasever = releasever self._yumCacheDirHack() self.gatherRepoMetadata() # trigger setup of self._yum.config logger.debug("installation yum config repos: %s" % ",".join([r.id for r in self._yum.repos.listEnabled()]))
def _addYumRepo(self, name, baseurl, mirrorlist=None, proxyurl=None, **kwargs): """ Add a yum repo to the YumBase instance. """ from yum.Errors import RepoError # First, delete any pre-existing repo with the same name. with _yum_lock: if name in self._yum.repos.repos: self._yum.repos.delete(name) logger.debug("adding yum repo %s with baseurl %s and mirrorlist %s" % (name, baseurl, mirrorlist)) with _yum_lock: # Then add it to yum's internal structures. obj = self._yum.add_enable_repo(name, baseurl=[baseurl], mirrorlist=mirrorlist, **kwargs) # this will trigger retrieval of repomd.xml, which is small and yet # gives us some assurance that the repo config is sane # YUMFIXME: yum's instant policy doesn't work as advertised obj.mdpolicy = "meh" try: obj.repoXML except RepoError as e: raise Exception( 'MetadataError', 'name: %s baseurl:%s err: %s' % (name, baseurl, e.value)) # Adding a new repo means the cached packages and groups lists # are out of date. Clear them out now so the next reference to # either will cause it to be regenerated. self._groups = None self._packages = []
def checkSoftwareSelection(self): logger.info("checking software selection") self.txID = time.time() self.release() with _yum_lock: self._yum._undoDepInstalls() self._applyYumSelections() with _yum_lock: # doPostSelection # select kernel packages # select packages needed for storage, bootloader # check dependencies logger.info("checking dependencies") (code, msgs) = self._yum.buildTransaction(unfinished_transactions_check=False) self._removeTxSaveFile() if code == 0: # empty transaction? logger.debug("empty transaction") elif code == 2: # success logger.debug("success") # elif self.data.packages.handleMissing == KS_MISSING_IGNORE: # logger.debug("ignoring missing due to ks config") # elif self.data.upgrade.upgrade: # logger.debug("ignoring unresolved deps on upgrade") else: for msg in msgs: logger.warning(msg) raise DependencyError(msgs) self.calculateSpaceNeeds() logger.info("%d packages selected totalling %s" % (len(self._yum.tsInfo.getMembers()), self.spaceRequired))
def _getRepoMetadata(self, yumrepo): """ Retrieve repo metadata if we don't already have it. """ from yum.Errors import RepoError, RepoMDError # And try to grab its metadata. We do this here so it can be done # on a per-repo basis, so we can then get some finer grained error # handling and recovery. logger.debug("getting repo metadata for %s" % yumrepo.id) with _yum_lock: try: yumrepo.getPrimaryXML() except RepoError as e: raise Exception('MetadataError', e.value) # Not getting group info is bad, but doesn't seem like a fatal error. # At the worst, it just means the groups won't be displayed in the UI # which isn't too bad, because you may be doing a kickstart install and # picking packages instead. logger.debug("getting group info for %s" % yumrepo.id) try: yumrepo.getGroups() except RepoMDError: logger.error("failed to get groups for repo %s" % yumrepo.id)
def install(self): """ Install the payload. """ from yum.Errors import PackageSackError, RepoError, YumBaseError logger.info("preparing transaction") logger.debug("initialize transaction set") with _yum_lock: self._yum.initActionTs() if rpmUtils and rpmUtils.arch.isMultiLibArch(): self._yum.ts.ts.setColor(3) logger.debug("populate transaction set") try: # uses dsCallback.transactionPopulation self._yum.populateTs(keepold=0) except RepoError as e: logger.error("error populating transaction: %s" % e) exn = PayloadInstallError(str(e)) #if errorHandler.cb(exn) == ERROR_RAISE: raise exn logger.debug("check transaction set") self._yum.ts.check() logger.debug("order transaction set") self._yum.ts.order() self._yum.ts.clean() # Write scriptlet output to a file to be logged later script_log = tempfile.NamedTemporaryFile(delete=False) self._yum.ts.ts.scriptFd = script_log.fileno() rpm.setLogFile(script_log) #@UndefinedVariable # create the install callback rpmcb = RPMCallback(self._yum, script_log, self.progress, upgrade=False) if self.flags.testing: self._yum.ts.setFlags( rpm.RPMTRANS_FLAG_TEST) #@UndefinedVariable logger.info("running transaction") self.progress.send_step() try: self._yum.runTransaction(cb=rpmcb) except PackageSackError as e: logger.error("error running transaction: %s" % e) exn = PayloadInstallError(str(e)) #if errorHandler.cb(exn) == ERROR_RAISE: raise exn except YumBaseError as e: logger.error("error [2] running transaction: %s" % e) for error in e.errors: logger.error("%s" % error[0]) exn = PayloadInstallError(str(e)) #if errorHandler.cb(exn) == ERROR_RAISE: raise exn else: logger.info("transaction complete") self.progress.send_step() finally: self._yum.ts.close() iutil.resetRpmDb() script_log.close() # log the contents of the scriptlet logfile logger.info("==== start rpm scriptlet logs ====") with open(script_log.name) as f: for l in f: logger.info(l) logger.info("==== end rpm scriptlet logs ====") os.unlink(script_log.name)
def enableRepo(self, repo_id): """ Enable a repo as specified by id. """ logger.debug("enabling repo %s" % repo_id) if repo_id in self.repos: self._yum.repos.enableRepo(repo_id)
def install(self): """ Install the payload. """ from yum.Errors import PackageSackError, RepoError, YumBaseError logger.info("preparing transaction") logger.debug("initialize transaction set") with _yum_lock: self._yum.initActionTs() if rpmUtils and rpmUtils.arch.isMultiLibArch(): self._yum.ts.ts.setColor(3) logger.debug("populate transaction set") try: # uses dsCallback.transactionPopulation self._yum.populateTs(keepold=0) except RepoError as e: logger.error("error populating transaction: %s" % e) exn = PayloadInstallError(str(e)) #if errorHandler.cb(exn) == ERROR_RAISE: raise exn logger.debug("check transaction set") self._yum.ts.check() logger.debug("order transaction set") self._yum.ts.order() self._yum.ts.clean() # Write scriptlet output to a file to be logged later script_log = tempfile.NamedTemporaryFile(delete=False) self._yum.ts.ts.scriptFd = script_log.fileno() rpm.setLogFile(script_log) #@UndefinedVariable # create the install callback rpmcb = RPMCallback(self._yum, script_log, self.progress, upgrade=False) if self.flags.testing: self._yum.ts.setFlags(rpm.RPMTRANS_FLAG_TEST) #@UndefinedVariable logger.info("running transaction") self.progress.send_step() try: self._yum.runTransaction(cb=rpmcb) except PackageSackError as e: logger.error("error running transaction: %s" % e) exn = PayloadInstallError(str(e)) #if errorHandler.cb(exn) == ERROR_RAISE: raise exn except YumBaseError as e: logger.error("error [2] running transaction: %s" % e) for error in e.errors: logger.error("%s" % error[0]) exn = PayloadInstallError(str(e)) #if errorHandler.cb(exn) == ERROR_RAISE: raise exn else: logger.info("transaction complete") self.progress.send_step() finally: self._yum.ts.close() iutil.resetRpmDb() script_log.close() # log the contents of the scriptlet logfile logger.info("==== start rpm scriptlet logs ====") with open(script_log.name) as f: for l in f: logger.info(l) logger.info("==== end rpm scriptlet logs ====") os.unlink(script_log.name)
def callback(self, event, amount, total, key, userdata): """ Yum install callback. """ if event == rpm.RPMCALLBACK_TRANS_START: #@UndefinedVariable if amount == 6: self.progress.send_message(_("Preparing transaction from installation source")) self.total_actions = total self.completed_actions = 0 elif event == rpm.RPMCALLBACK_TRANS_PROGRESS: #@UndefinedVariable # amount / total complete pass elif event == rpm.RPMCALLBACK_TRANS_STOP: #@UndefinedVariable # we are done pass elif event == rpm.RPMCALLBACK_INST_OPEN_FILE: #@UndefinedVariable # update status that we're installing/upgrading %h # return an open fd to the file txmbr = self._get_txmbr(key)[1] # If self.completed_actions is still None, that means this package # is being opened to retrieve a %pretrans script. Don't log that # we're installing the package unless we've been called with a # TRANS_START event. if self.completed_actions is not None: if self.upgrade: mode = _("Upgrading") else: mode = _("Installing") self.completed_actions += 1 msg_format = "%s %s (%d/%d)" progress_package = txmbr.name if txmbr.arch not in ["noarch", self.base_arch]: progress_package = "%s.%s" % (txmbr.name, txmbr.arch) progress_msg = msg_format % (mode, progress_package, self.completed_actions, self.total_actions) log_msg = msg_format % (mode, txmbr.po, self.completed_actions, self.total_actions) logger.info(log_msg) self.install_log.write(log_msg+"\n") self.install_log.flush() self.progress.send_message(progress_msg) self.package_file = None repo = self._yum.repos.getRepo(txmbr.po.repoid) while self.package_file is None: try: # checkfunc gets passed to yum's use of URLGrabber which # then calls it with the file being fetched. verifyPkg # makes sure the checksum matches the one in the metadata. # # From the URLGrab documents: # checkfunc=(function, ('arg1', 2), {'kwarg': 3}) # results in a callback like: # function(obj, 'arg1', 2, kwarg=3) # obj.filename = '/tmp/stuff' # obj.url = 'http://foo.com/stuff' checkfunc = (self._yum.verifyPkg, (txmbr.po, 1), {}) package_path = repo.getPackage(txmbr.po, checkfunc=checkfunc) except yum.URLGrabError as e: logger.error("URLGrabError: %s" % (e,)) exn = PayloadInstallError("failed to get package") #if errorHandler.cb(exn, txmbr.po) == ERROR_RAISE: raise exn except (yum.Errors.NoMoreMirrorsRepoError, IOError): if os.path.exists(txmbr.po.localPkg()): os.unlink(txmbr.po.localPkg()) logger.debug("retrying download of %s" % txmbr.po) continue exn = PayloadInstallError("failed to open package") #if errorHandler.cb(exn, txmbr.po) == ERROR_RAISE: raise exn except yum.Errors.RepoError: continue self.package_file = open(package_path) return self.package_file.fileno() elif event == rpm.RPMCALLBACK_INST_PROGRESS: #@UndefinedVariable txmbr = self._get_txmbr(key)[1] progress_package = txmbr.name if txmbr.arch not in ["noarch", self.base_arch]: progress_package = "%s.%s" % (txmbr.name, txmbr.arch) #self.progress.send_message('%s (%s/%s)' % (progress_package, amount, total)) elif event == rpm.RPMCALLBACK_INST_CLOSE_FILE: #@UndefinedVariable # close and remove the last opened file # update count of installed/upgraded packages package_path = self.package_file.name self.package_file.close() self.package_file = None if package_path.startswith(_yum_cache_dir): try: os.unlink(package_path) except OSError as e: logger.debug("unable to remove file %s" % e.strerror) # rpm doesn't tell us when it's started post-trans stuff which can # take a very long time. So when it closes the last package, just # display the message. if self.completed_actions == self.total_actions: self.progress.send_message(_("Performing post-install setup tasks")) elif event == rpm.RPMCALLBACK_UNINST_START: #@UndefinedVariable # update status that we're cleaning up %key #self.progress.set_text(_("Cleaning up %s" % key)) pass elif event in (rpm.RPMCALLBACK_CPIO_ERROR, #@UndefinedVariable rpm.RPMCALLBACK_UNPACK_ERROR, #@UndefinedVariable rpm.RPMCALLBACK_SCRIPT_ERROR): #@UndefinedVariable name = self._get_txmbr(key)[0] # Script errors store whether or not they're fatal in "total". So, # we should only error out for fatal script errors or the cpio and # unpack problems. if event != rpm.RPMCALLBACK_SCRIPT_ERROR or total: #@UndefinedVariable exn = PayloadInstallError("cpio, unpack, or fatal script error") #if errorHandler.cb(exn, name) == ERROR_RAISE: raise exn
def callback(self, event, amount, total, key, userdata): """ Yum install callback. """ if event == rpm.RPMCALLBACK_TRANS_START: #@UndefinedVariable if amount == 6: self.progress.send_message( _("Preparing transaction from installation source")) self.total_actions = total self.completed_actions = 0 elif event == rpm.RPMCALLBACK_TRANS_PROGRESS: #@UndefinedVariable # amount / total complete pass elif event == rpm.RPMCALLBACK_TRANS_STOP: #@UndefinedVariable # we are done pass elif event == rpm.RPMCALLBACK_INST_OPEN_FILE: #@UndefinedVariable # update status that we're installing/upgrading %h # return an open fd to the file txmbr = self._get_txmbr(key)[1] # If self.completed_actions is still None, that means this package # is being opened to retrieve a %pretrans script. Don't log that # we're installing the package unless we've been called with a # TRANS_START event. if self.completed_actions is not None: if self.upgrade: mode = _("Upgrading") else: mode = _("Installing") self.completed_actions += 1 msg_format = "%s %s (%d/%d)" progress_package = txmbr.name if txmbr.arch not in ["noarch", self.base_arch]: progress_package = "%s.%s" % (txmbr.name, txmbr.arch) progress_msg = msg_format % (mode, progress_package, self.completed_actions, self.total_actions) log_msg = msg_format % (mode, txmbr.po, self.completed_actions, self.total_actions) logger.info(log_msg) self.install_log.write(log_msg + "\n") self.install_log.flush() self.progress.send_message(progress_msg) self.package_file = None repo = self._yum.repos.getRepo(txmbr.po.repoid) while self.package_file is None: try: # checkfunc gets passed to yum's use of URLGrabber which # then calls it with the file being fetched. verifyPkg # makes sure the checksum matches the one in the metadata. # # From the URLGrab documents: # checkfunc=(function, ('arg1', 2), {'kwarg': 3}) # results in a callback like: # function(obj, 'arg1', 2, kwarg=3) # obj.filename = '/tmp/stuff' # obj.url = 'http://foo.com/stuff' checkfunc = (self._yum.verifyPkg, (txmbr.po, 1), {}) package_path = repo.getPackage(txmbr.po, checkfunc=checkfunc) except yum.URLGrabError as e: logger.error("URLGrabError: %s" % (e, )) exn = PayloadInstallError("failed to get package") #if errorHandler.cb(exn, txmbr.po) == ERROR_RAISE: raise exn except (yum.Errors.NoMoreMirrorsRepoError, IOError): if os.path.exists(txmbr.po.localPkg()): os.unlink(txmbr.po.localPkg()) logger.debug("retrying download of %s" % txmbr.po) continue exn = PayloadInstallError("failed to open package") #if errorHandler.cb(exn, txmbr.po) == ERROR_RAISE: raise exn except yum.Errors.RepoError: continue self.package_file = open(package_path) return self.package_file.fileno() elif event == rpm.RPMCALLBACK_INST_PROGRESS: #@UndefinedVariable txmbr = self._get_txmbr(key)[1] progress_package = txmbr.name if txmbr.arch not in ["noarch", self.base_arch]: progress_package = "%s.%s" % (txmbr.name, txmbr.arch) #self.progress.send_message('%s (%s/%s)' % (progress_package, amount, total)) elif event == rpm.RPMCALLBACK_INST_CLOSE_FILE: #@UndefinedVariable # close and remove the last opened file # update count of installed/upgraded packages package_path = self.package_file.name self.package_file.close() self.package_file = None if package_path.startswith(_yum_cache_dir): try: os.unlink(package_path) except OSError as e: logger.debug("unable to remove file %s" % e.strerror) # rpm doesn't tell us when it's started post-trans stuff which can # take a very long time. So when it closes the last package, just # display the message. if self.completed_actions == self.total_actions: self.progress.send_message( _("Performing post-install setup tasks")) elif event == rpm.RPMCALLBACK_UNINST_START: #@UndefinedVariable # update status that we're cleaning up %key #self.progress.set_text(_("Cleaning up %s" % key)) pass elif event in ( rpm.RPMCALLBACK_CPIO_ERROR, #@UndefinedVariable rpm.RPMCALLBACK_UNPACK_ERROR, #@UndefinedVariable rpm.RPMCALLBACK_SCRIPT_ERROR): #@UndefinedVariable name = self._get_txmbr(key)[0] # Script errors store whether or not they're fatal in "total". So, # we should only error out for fatal script errors or the cpio and # unpack problems. if event != rpm.RPMCALLBACK_SCRIPT_ERROR or total: #@UndefinedVariable exn = PayloadInstallError( "cpio, unpack, or fatal script error") #if errorHandler.cb(exn, name) == ERROR_RAISE: raise exn