def run(self): """Execute the command.""" path = self.opts.filename[0] try: packages = parse_kickstart_packages(path) except pykickstart.errors.KickstartError: raise dnf.exceptions.Error(_('file cannot be parsed: %s') % path) group_names = [group.name for group in packages.groupList] if group_names: self.base.read_comps() try: self.base.install_grouplist(group_names) are_groups_installed = True except dnf.exceptions.Error: are_groups_installed = False are_packages_installed = False for pattern in packages.packageList: try: self.base.install(pattern) except dnf.exceptions.MarkingError: logger.info(_('No package %s available.'), pattern) else: are_packages_installed = True if not are_groups_installed and not are_packages_installed: raise dnf.exceptions.Error(_('Nothing to do.'))
def run_upgrade(self): # change the upgrade status (so we can detect crashed upgrades later) command = '' with self.state as state: state.upgrade_status = 'incomplete' command = state.upgrade_command if command == 'offline-upgrade': msg = _("Starting offline upgrade. This will take a while.") elif command == 'offline-distrosync': msg = _("Starting offline distrosync. This will take a while.") else: msg = _("Starting system upgrade. This will take a while.") self.log_status(msg, UPGRADE_STARTED_ID) # reset the splash mode and let the user know we're running Plymouth.set_mode() Plymouth.progress(0) Plymouth.message(msg) # disable screen blanking disable_blanking() self.replay = TransactionReplay(self.base, self.transaction_file) self.replay.run()
def configure_download(self): if 'system-upgrade' == self.opts.command or 'fedup' == self.opts.command: help_url = get_url_from_os_release() if help_url: msg = _('Additional information for System Upgrade: {}') logger.info(msg.format(ucd(help_url))) if self.base._promptWanted(): msg = _( 'Before you continue ensure that your system is fully upgraded by running ' '"dnf --refresh upgrade". Do you want to continue') if self.base.conf.assumeno or not self.base.output.userconfirm( msg='{} [y/N]: '.format(msg), defaultyes_msg='{} [Y/n]: '.format(msg)): logger.error(_("Operation aborted.")) sys.exit(1) check_release_ver(self.base.conf, target=self.opts.releasever) self.cli.demands.root_user = True self.cli.demands.resolving = True self.cli.demands.available_repos = True self.cli.demands.sack_activation = True self.cli.demands.freshest_metadata = True # We want to do the depsolve / download / transaction-test, but *not* # run the actual RPM transaction to install the downloaded packages. # Setting the "test" flag makes the RPM transaction a test transaction, # so nothing actually gets installed. # (It also means that we run two test transactions in a row, which is # kind of silly, but that's something for DNF to fix...) self.base.conf.tsflags += ["test"]
def render_error(err): print("Tracer:") print(" " + _("Call to Tracer API ended unexpectedly:") + "\n") print(err) print(_("Please visit https://github.com/FrostyX/tracer/issues " "and submit the issue. Thank you")) print(_("We apologize for any inconvenience"))
def transaction_upgrade(self): Plymouth.message(_("Upgrade complete! Cleaning up and rebooting...")) self.log_status(_("Upgrade complete! Cleaning up and rebooting..."), UPGRADE_FINISHED_ID) self.run_clean() if self.opts.tid[0] == "upgrade": reboot()
def pre_transaction(self): if not self.base.transaction: return try: bus = SystemBus() self._snapper = Interface(bus.get_object('org.opensuse.Snapper', '/org/opensuse/Snapper'), dbus_interface='org.opensuse.Snapper') except DBusException as e: logger.critical( "snapper: " + _("connect to snapperd failed: %s"), e ) return try: logger.debug( "snapper: " + _("creating pre_snapshot") ) self._pre_snap_number = self._snapper.CreatePreSnapshot("root", self.description, "number", {}) self._pre_snap_created = True logger.debug( "snapper: " + _("created pre_snapshot %d"), self._pre_snap_number ) except DBusException as e: logger.critical( "snapper: " + _("creating pre_snapshot failed: %s"), e )
def run(self): """Execute the command.""" path = self.opts.filename[0] try: packages = parse_kickstart_packages(path) except pykickstart.errors.KickstartError: raise dnf.exceptions.Error(_('file cannot be parsed: %s') % path) group_names = [group.name for group in packages.groupList] if group_names: self.base.read_comps() try: self.base.install_grouplist(group_names) except dnf.exceptions.Error: are_groups_installed = False else: are_groups_installed = True are_packages_installed = False for pattern in packages.packageList: try: self.base.install(pattern) except dnf.exceptions.MarkingError: logger.info(_('No package %s available.'), pattern) else: are_packages_installed = True if not are_groups_installed and not are_packages_installed: raise dnf.exceptions.Error(_('Nothing to do.'))
def set_argparser(parser): parser.add_argument("--no-downgrade", dest='distro_sync', action='store_false', help=_("keep installed packages if the new " "release's version is older")) parser.add_argument('tid', nargs=1, choices=CMDS, metavar="[%s]" % "|".join(CMDS)) parser.add_argument('--number', type=int, help=_('which logs to show'))
def render_error(err): print("Tracer:") print(" " + _("Call to Tracer API ended unexpectedly:") + "\n") print(err) print( _("Please visit https://github.com/FrostyX/tracer/issues " "and submit the issue. Thank you")) print(_("We apologize for any inconvenience"))
def check_upgrade(self): if not self.state.upgrade_status == 'ready': raise CliError( # Translators: do not change "reboot" here _("use 'dnf system-upgrade reboot' to begin the upgrade")) if os.readlink(MAGIC_SYMLINK) != DEFAULT_DATADIR: logger.info(_("another upgrade tool is running. exiting quietly.")) raise SystemExit(0) # Delete symlink ASAP to avoid reboot loops dnf.yum.misc.unlink_f(MAGIC_SYMLINK)
def list_logs(): print(_('The following boots appear to contain upgrade logs:')) n = -1 for n, entry in enumerate(find_boots(ID_TO_IDENTIFY_BOOTS)): print('{} / {.hex}: {:%Y-%m-%d %H:%M:%S} {}→{}'.format( n + 1, entry['_BOOT_ID'], entry['__REALTIME_TIMESTAMP'], entry.get('SYSTEM_RELEASEVER', '??'), entry.get('TARGET_RELEASEVER', '??'))) if n == -1: print(_('-- no logs were found --'))
def check_reboot(self): if not self.state.download_status == 'complete': raise CliError(_("system is not ready for upgrade")) self._check_state_version(self.opts.command) if self.state.upgrade_command != self.opts.command: msg = _("the transaction was not prepared for '{command}'. " "Rerun 'dnf {command} download [OPTIONS]'").format(command=self.opts.command) raise CliError(msg) if os.path.lexists(MAGIC_SYMLINK): raise CliError(_("upgrade is already scheduled")) dnf.util.ensure_dir(DEFAULT_DATADIR)
def run_upgrade(self): # change the upgrade status (so we can detect crashed upgrades later) with self.state as state: state.upgrade_status = 'incomplete' self.log_status(_("Starting system upgrade. This will take a while."), UPGRADE_STARTED_ID) # reset the splash mode and let the user know we're running Plymouth.set_mode() Plymouth.progress(0) Plymouth.message(_("Starting system upgrade. This will take a while.")) # disable screen blanking disable_blanking() # NOTE: We *assume* that depsolving here will yield the same # transaction as it did during the download, but we aren't doing # anything to *ensure* that; if the metadata changed, or if depsolving # is non-deterministic in some way, we could end up with a different # transaction and then the upgrade will fail due to missing packages. # # One way to *guarantee* that we have the same transaction would be # to save & restore the Transaction object, but there's no documented # way to save a Transaction to disk. # # So far, though, the above assumption seems to hold. So... onward! # add the downloaded RPMs to the sack errs = [] for pkgspec in self.state.remove_packages: try: self.base.remove(pkgspec) except dnf.exceptions.MarkingError: msg = _('Unable to match package: %s') logger.info(msg, self.base.output.term.bold(pkgspec)) errs.append(pkgspec) for repo_id, pkg_spec_list in self.state.install_packages.items(): for pkgspec in pkg_spec_list: try: self.base.install(pkgspec, reponame=repo_id) except dnf.exceptions.MarkingError: msg = _('Unable to match package: %s') logger.info( msg, self.base.output.term.bold(pkgspec + " " + repo_id)) errs.append(pkgspec) if errs: raise dnf.exceptions.MarkingError( _("Unable to match some of packages"))
def doCheck(self, basecmd, extcmds): """Verify that conditions are met so that this command can run.""" dnf.cli.commands.checkGPGKey(self.base, self.cli) try: self.parse_extcmds(extcmds) except ValueError: logger.critical( _('Error: Requires exactly one path to a kickstart file')) dnf.cli.commands.err_mini_usage(self.cli, basecmd) raise dnf.cli.CliError( _('exactly one path to a kickstart file required')) dnf.cli.commands.checkEnabledRepo(self.base, extcmds)
def check_upgrade(self): if not os.path.lexists(MAGIC_SYMLINK): logger.info(_("trigger file does not exist. exiting quietly.")) raise SystemExit(0) if os.readlink(MAGIC_SYMLINK) != DEFAULT_DATADIR: logger.info(_("another upgrade tool is running. exiting quietly.")) raise SystemExit(0) # Delete symlink ASAP to avoid reboot loops dnf.yum.misc.unlink_f(MAGIC_SYMLINK) command = self.state.upgrade_command if not command: command = self.opts.command self._check_state_version(command) if not self.state.upgrade_status == 'ready': msg = _("use 'dnf {command} reboot' to begin the upgrade").format(command=command) raise CliError(msg)
def run(self): """Execute the command.""" path = self.opts.filename[0] try: packages = parse_kickstart_packages(path) except pykickstart.errors.KickstartError: raise dnf.exceptions.Error(_('file cannot be parsed: %s') % path) include_list = ["@{}".format(group.name) for group in packages.groupList] exclude_list = ["@{}".format(group.name) for group in packages.excludedGroupList] if include_list: self.base.read_comps() # handle packages for pkg_name in packages.excludedList: exclude_list.append(pkg_name) for pkg_name in packages.packageList: include_list.append(pkg_name) try: self.base.install_specs(install=include_list, exclude=exclude_list) except dnf.exceptions.MarkingErrors as e: if self.base.conf.strict: if e.no_match_group_specs or e.error_group_specs or e.no_match_pkg_specs or \ e.error_pkg_specs: raise if e.module_depsolv_errors and e.module_depsolv_errors[1] != \ libdnf.module.ModulePackageContainer.ModuleErrorType_ERROR_IN_DEFAULTS: raise logger.error(str(e)) except dnf.exceptions.Error as e: if self.base.conf.strict: raise logger.error(str(e))
def transaction(self): """ Call after successful transaction See https://rpm-software-management.github.io/dnf/api_transaction.html """ # Don't run tracer when preparing chroot for mock if self.base.conf.installroot != "/": return # Don't run tracer when "nothing to do" if not len(self.base.transaction): return installed = set( [package.name for package in self.base.transaction.install_set]) erased = set( [package.name for package in self.base.transaction.remove_set]) packages = [Package(p, time.time()) for p in list(installed | erased)] try: tracer = TracerFacade(packages) tracer.render() if len(tracer.apps) != 0: print("\n" + _("For more information run:")) print(" sudo tracer -iat " + str(self.timestamp)) except Exception: render_error(traceback.format_exc())
def run_clean(self): logger.info(_("Cleaning up downloaded data...")) clear_dir(DEFAULT_DATADIR) with self.state as state: state.download_status = None state.upgrade_status = None state.install_packages = {}
def transaction_download(self): downloads = self.cli.base.transaction.install_set install_packages = {} for pkg in downloads: install_packages.setdefault(pkg.repo.id, []).append(str(pkg)) remove_packages = [ str(pkg) for pkg in self.cli.base.transaction.remove_set ] # Okay! Write out the state so the upgrade can use it. system_ver = dnf.rpm.detect_releasever(self.base.conf.installroot) with self.state as state: state.download_status = 'complete' state.distro_sync = self.opts.distro_sync state.allow_erasing = self.cli.demands.allow_erasing state.gpgcheck = self.base.conf.gpgcheck state.gpgcheck_repos = [ repo.id for repo in self.base.repos.values() if repo.gpgcheck ] state.repo_gpgcheck_repos = [ repo.id for repo in self.base.repos.values() if repo.repo_gpgcheck ] state.best = self.base.conf.best state.system_releasever = system_ver state.target_releasever = self.base.conf.releasever state.install_packages = install_packages state.remove_packages = remove_packages state.install_weak_deps = self.base.conf.install_weak_deps state.module_platform_id = self.base.conf.module_platform_id state.enable_disable_repos = self.opts.repos_ed state.destdir = self.base.conf.destdir logger.info(DOWNLOAD_FINISHED_MSG) self.log_status(_("Download finished."), DOWNLOAD_FINISHED_ID)
def transaction_download(self): install_packages, remove_packages = self._get_forward_reverse_pkg_reason_pairs( ) # Okay! Write out the state so the upgrade can use it. system_ver = dnf.rpm.detect_releasever(self.base.conf.installroot) with self.state as state: state.download_status = 'complete' state.state_version = STATE_VERSION state.distro_sync = self.opts.distro_sync state.allow_erasing = self.cli.demands.allow_erasing state.gpgcheck = self.base.conf.gpgcheck state.gpgcheck_repos = [ repo.id for repo in self.base.repos.values() if repo.gpgcheck ] state.repo_gpgcheck_repos = [ repo.id for repo in self.base.repos.values() if repo.repo_gpgcheck ] state.best = self.base.conf.best state.system_releasever = system_ver state.target_releasever = self.base.conf.releasever state.install_packages = install_packages state.remove_packages = remove_packages state.install_weak_deps = self.base.conf.install_weak_deps state.module_platform_id = self.base.conf.module_platform_id state.enable_disable_repos = self.opts.repos_ed state.destdir = self.base.conf.destdir state.upgrade_command = self.opts.command msg = DOWNLOAD_FINISHED_MSG.format(command=self.opts.command) logger.info(msg) self.log_status(_("Download finished."), DOWNLOAD_FINISHED_ID)
def show_log(n): boot_id = pick_boot(ID_TO_IDENTIFY_BOOTS, n) process = Popen(['journalctl', '--boot', boot_id.hex]) process.wait() rc = process.returncode if rc == 1: raise dnf.exceptions.Error(_("Unable to match systemd journal entry"))
def transaction(self): """ Call after successful transaction See https://rpm-software-management.github.io/dnf/api_transaction.html """ # Don't run tracer when preparing chroot for mock if self.base.conf.installroot != "/": return # Don't run tracer when "nothing to do" if not len(self.base.transaction): return installed = set([package.name for package in self.base.transaction.install_set]) erased = set([package.name for package in self.base.transaction.remove_set]) packages = [Package(p, time.time()) for p in list(installed | erased)] try: tracer = TracerFacade(packages) tracer.render() if len(tracer.apps) != 0: print("\n" + _("For more information run:")) print(" sudo tracer -iat " + str(self.timestamp)) except Exception: render_error(traceback.format_exc())
def transaction(self): if not self._pre_snap_created: logger.debug("snapper: " + _( "skipping post_snapshot because creation of pre_snapshot failed" )) return try: logger.debug("snapper: " + _("creating post_snapshot")) snap_post_number = self._snapper.CreatePostSnapshot( "root", self._pre_snap_number, self.description, "number", {}) logger.debug("snapper: " + _("created post_snapshot %d"), snap_post_number) except DBusException as e: logger.critical( "snapper: " + _("creating post_snapshot failed: %s"), e)
def resolved(self): tmp = [] for trans_item in self.base.transaction: tmp.append(trans_item.installs()) for packages in tmp: for pkg in packages: logger.debug(_("Adding '{}' to list of handling " "packages for rpmconf").format(pkg.name)) self.packages.append(pkg.name)
def transaction_download(self): transaction = self.base.history.get_current() if not transaction.packages(): logger.info( _("The system-upgrade transaction is empty, your system is already up-to-date." )) return data = serialize_transaction(transaction) try: with open(self.transaction_file, "w") as f: json.dump(data, f, indent=4, sort_keys=True) f.write("\n") print(_("Transaction saved to {}.").format(self.transaction_file)) except OSError as e: raise dnf.cli.CliError( _('Error storing transaction: {}').format(str(e))) # Okay! Write out the state so the upgrade can use it. system_ver = dnf.rpm.detect_releasever(self.base.conf.installroot) with self.state as state: state.download_status = 'complete' state.state_version = STATE_VERSION state.distro_sync = self.opts.distro_sync state.gpgcheck = self.base.conf.gpgcheck state.gpgcheck_repos = [ repo.id for repo in self.base.repos.values() if repo.gpgcheck ] state.repo_gpgcheck_repos = [ repo.id for repo in self.base.repos.values() if repo.repo_gpgcheck ] state.system_releasever = system_ver state.target_releasever = self.base.conf.releasever state.module_platform_id = self.base.conf.module_platform_id state.enable_disable_repos = self.opts.repos_ed state.destdir = self.base.conf.destdir state.upgrade_command = self.opts.command msg = DOWNLOAD_FINISHED_MSG.format(command=self.opts.command) logger.info(msg) self.log_status(_("Download finished."), DOWNLOAD_FINISHED_ID)
def resolved(self): if not self._interactive: return for pkg in self.base.transaction.install_set: logger.debug( _("Adding '{}' to list of handling " "packages for rpmconf").format(pkg.name)) self.packages.append(pkg.name)
class KickstartCommand(dnf.cli.Command): """A command installing groups/packages defined in kickstart files.""" aliases = ('kickstart', ) summary = _("Install packages defined in a kickstart file on your system") @staticmethod def set_argparser(parser): parser.add_argument("filename", nargs=1, help=_("kickstart file")) def configure(self): demands = self.cli.demands demands.resolving = True demands.root_user = True demands.sack_activation = True dnf.cli.commands._checkGPGKey(self.base, self.cli) dnf.cli.commands._checkEnabledRepo(self.base, self.opts.filename[0]) def run(self): """Execute the command.""" path = self.opts.filename[0] try: packages = parse_kickstart_packages(path) except pykickstart.errors.KickstartError: raise dnf.exceptions.Error(_('file cannot be parsed: %s') % path) include_list = [ "@{}".format(group.name) for group in packages.groupList ] exclude_list = [ "@{}".format(group.name) for group in packages.excludedGroupList ] if include_list: self.base.read_comps() # handle packages for pkg_name in packages.excludedList: exclude_list.append(pkg_name) for pkg_name in packages.packageList: include_list.append(pkg_name) try: self.base.install_specs(install=include_list, exclude=exclude_list) except dnf.exceptions.MarkingErrors as e: if self.base.conf.strict: if e.no_match_group_specs or e.error_group_specs or e.no_match_pkg_specs or \ e.error_pkg_specs: raise if e.module_depsolv_errors and e.module_depsolv_errors[1] != \ libdnf.module.ModulePackageContainer.ModuleErrorType_ERROR_IN_DEFAULTS: raise logger.error(str(e)) except dnf.exceptions.Error as e: if self.base.conf.strict: raise logger.error(str(e))
def run_reboot(self): self.run_prepare() if not self.opts.tid[0] == "reboot": return self.log_status(_("Rebooting to perform upgrade."), REBOOT_REQUESTED_ID) reboot()
def pre_configure_download(self): # only download subcommand accepts --destdir command line option self.base.conf.cachedir = DEFAULT_DATADIR self.base.conf.destdir = self.opts.destdir if self.opts.destdir else None if 'offline-distrosync' == self.opts.command and not self.opts.distro_sync: raise CliError( _("Command 'offline-distrosync' cannot be used with --no-downgrade option")) elif 'offline-upgrade' == self.opts.command: self.opts.distro_sync = False
def run_clean(self): logger.info(_("Cleaning up downloaded data...")) clear_dir(self.base.conf.cachedir) if self.base.conf.destdir: clear_dir(self.base.conf.destdir) with self.state as state: state.download_status = None state.upgrade_status = None state.destdir = None state.install_packages = {}
def _read(self): try: with open(self.statefile) as fp: self._data = json.load(fp) except IOError: self._data = {} except ValueError: self._data = {} logger.warning(_("Failed loading state file: %s, continuing with " "empty state."), self.statefile)
def configure_download(self): if self.base._promptWanted(): msg = _('Before you continue ensure that your system is fully upgraded by running ' '"dnf --refresh upgrade". Do you want to continue') if self.base.conf.assumeno or not self.base.output.userconfirm( msg='{} [y/N]: '.format(msg), defaultyes_msg='{} [Y/n]: '.format(msg)): raise CliError(_("Operation aborted.")) self.cli.demands.root_user = True self.cli.demands.resolving = True self.cli.demands.available_repos = True self.cli.demands.sack_activation = True self.cli.demands.freshest_metadata = True # We want to do the depsolve / download / transaction-test, but *not* # run the actual RPM transaction to install the downloaded packages. # Setting the "test" flag makes the RPM transaction a test transaction, # so nothing actually gets installed. # (It also means that we run two test transactions in a row, which is # kind of silly, but that's something for DNF to fix...) self.base.conf.tsflags += ["test"]
def resolved(self): tmp = [] for trans_item in self.base.transaction: tmp.append(trans_item.installs()) for packages in tmp: for pkg in packages: logger.debug( _("Adding '{}' to list of handling " "packages for rpmconf").format(pkg.name)) self.packages.append(pkg.name)
def transaction(self): if not self._interactive: logger.debug(_("rpmconf plugin will not run " "in non-interactive mode")) return rconf = rpmconf.RpmConf( packages=self.packages, frontend=self.frontend, diff=self.diff) try: rconf.run() except SystemExit as e: if e.code == errno.ENOENT: logger.debug( _("ignoring sys.exit from rpmconf " "due to missing MERGE variable")) elif e.code == errno.EINTR: logger.debug( _("ignoring sys.exit from rpmconf " "due to missing file"))
def transaction(self): if not self._interactive: logger.debug( _("rpmconf plugin will not run " "in non-interactive mode")) return rconf = rpmconf.RpmConf(packages=self.packages, frontend=self.frontend, diff=self.diff) try: rconf.run() except SystemExit as e: if e.code == errno.ENOENT: logger.debug( _("ignoring sys.exit from rpmconf " "due to missing MERGE variable")) elif e.code == errno.EINTR: logger.debug( _("ignoring sys.exit from rpmconf " "due to missing file"))
def pick_boot(message_id, n): boots = list(find_boots(message_id)) # Positive indices index all found boots starting with 1 and going forward, # zero is the current boot, and -1, -2, -3 are previous going backwards. # This is the same as journalctl. try: if n == 0: raise IndexError if n > 0: n -= 1 return boots[n]['_BOOT_ID'] except IndexError: raise CliError(_("Cannot find logs with this index."))
def transaction(self): if not self.base.transaction: return if not self._pre_snap_created: logger.debug( "snapper: " + _("skipping post_snapshot because creation of pre_snapshot failed") ) return try: logger.debug( "snapper: " + _("creating post_snapshot") ) snap_post_number = self._snapper.CreatePostSnapshot("root", self._pre_snap_number, self.description, "number", {}) logger.debug( "snapper: " + _("created post_snapshot %d"), snap_post_number ) except DBusException as e: logger.critical( "snapper: " + _("creating post_snapshot failed: %s"), e )
def set_argparser(parser): parser.add_argument("filename", nargs=1, help=_("kickstart file"))
# source code or documentation are not subject to the GNU General Public # License and may only be used or replicated with the express permission of # Red Hat, Inc. # import json import io import pycurl from dnfpluginsextras import _, logger import dnf import dnf.plugin MSG = _('Disabling torproxy plugin: cannot connect to the Tor network') class TorProxy(dnf.Plugin): name = "torproxy" def __init__(self, base, cli): super(TorProxy, self).__init__(base, cli) self.base = base self._host = '127.0.0.1' self._port = '9050' def _check_tor_working(self): buf = io.BytesIO()
from __future__ import absolute_import from __future__ import unicode_literals from dnfpluginsextras import _, logger import dnf import dnf.cli import dnf.exceptions import fnmatch import hawkey import os import tempfile import time PLUGIN_CONF = 'versionlock' NOT_READABLE = _('Unable to read version lock configuration: %s') NO_LOCKLIST = _('Locklist not set') ADDING_SPEC = _('Adding versionlock on:') EXCLUDING_SPEC = _('Adding exclude on:') DELETING_SPEC = _('Deleting versionlock for:') NOTFOUND_SPEC = _('No package found for:') locklist_fn = None class VersionLock(dnf.Plugin): name = 'versionlock' def __init__(self, base, cli): super(VersionLock, self).__init__(base, cli) self.base = base