commit 9f7f2aa04e7ca5bece6bf42c5ea038466e814abe Author: James Antill Date: Mon Jun 21 17:30:26 2010 -0400 Add ps plugin, to show info about running commands. diff --git a/plugins/ps/ps.conf b/plugins/ps/ps.conf new file mode 100644 index 0000000..8e4d76c --- /dev/null +++ b/plugins/ps/ps.conf @@ -0,0 +1,2 @@ +[main] +enabled=1 diff --git a/plugins/ps/ps.py b/plugins/ps/ps.py new file mode 100644 index 0000000..d58fc61 --- /dev/null +++ b/plugins/ps/ps.py @@ -0,0 +1,166 @@ +#! /usr/bin/python -tt +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# +# Copyright Red Hat Inc. 2010 +# +# Author: James Antill +# +# Examples: +# +# yum ps k\* +# yum ps all + +import yum +import yum.misc as misc +from yum.plugins import TYPE_INTERACTIVE + +from urlgrabber.progress import format_number +import utils + +import fnmatch +import time + +requires_api_version = '2.5' +plugin_type = (TYPE_INTERACTIVE,) + + +class PSCommand: + def getNames(self): + return ['ps'] + + def getUsage(self): + return "[all|updates|restart] [pkgs...]" + + def getSummary(self): + return "List processes, which are packages" + + def doCheck(self, base, basecmd, extcmds): + pass + + def doCommand(self, base, basecmd, extcmds): + show_all = False + show_upgrades = False + if extcmds and extcmds[0] == 'all': + show_all = True + extcmds = extcmds[1:] + elif extcmds and extcmds[0] in ('updates', 'upgrades'): + show_upgrades = True + extcmds = extcmds[1:] + elif extcmds and extcmds[0] == 'restarts': + extcmds = extcmds[1:] + + pkgs = base.rpmdb.return_running_packages(return_pids=True) + ts = base.rpmdb.readOnlyTS() + kern_pkgtup = misc.get_running_kernel_pkgtup(ts) + kern_pkg = None + for pkg in sorted(base.rpmdb.searchPkgTuple(kern_pkgtup)): + kern_pkg = pkg + if kern_pkg is not None: + kern_pkgs = base.rpmdb.searchNames([kern_pkgtup[0]]) + if kern_pkgs: + kern_latest = sorted(kern_pkgs)[-1] + if kern_latest.verGT(kern_pkg): + pkgs[kern_latest] = [0] + + try: + # Get boot time, this is what get_process_info() uses: + for line in open("/proc/stat"): + if line.startswith("btime "): + kern_boot = int(line[len("btime "):-1]) + break + except: + kern_boot = 0 + + print " %8s %-16s %8s %8s %10s %s" % ("pid", "proc", + "CPU", "RSS", "State", "uptime") + for pkg in sorted(pkgs): + if extcmds: + for cmd in extcmds: + if fnmatch.fnmatch(pkg.name, cmd): + break + if fnmatch.fnmatch(pkg.ui_nevra, cmd): + break + else: + continue + + apkgs = base.pkgSack.searchNames([pkg.name]) + state = '' + if not apkgs: + apkgs = 'Not available!' + else: + apkgs = sorted(apkgs)[-1] + if apkgs.verEQ(pkg): + apkgs = '' + state = '' + elif apkgs.verGT(pkg): + state = 'Upgrade' + apkgs = apkgs.ui_nevra[len(apkgs.name)+1:] + else: + state = 'Newer' + apkgs = apkgs.ui_nevra[len(apkgs.name)+1:] + procs = [] + for pid in pkgs[pkg]: + pid = int(pid) + now = int(time.time()) + if pid: + ps_info = utils.get_process_info(pid) + if ps_info is None: + ps_info = {'name' : '', + 'start_time' : 0, + 'state' : 'Unknown', + 'vmrss' : 0, 'utime' : 0, 'stime' : 0} + else: + ps_info = {'name' : '', + 'start_time' : kern_boot, + 'state' : 'Running', + 'vmrss' : 0, 'utime' : 0, 'stime' : 0} + procs.append((ps_info['start_time'], pid, ps_info)) + oldest_proc = min([t[0] for t in procs]) + if show_all: + pass + elif oldest_proc < pkg.installtime: + pass + elif show_upgrades and state == 'Upgrade': + pass + else: + continue + print "%s %s %s" % (pkg, state, apkgs) + for start_time, pid, ps_info in sorted(procs): + ago = utils.seconds_to_ui_time(now - start_time) + nr = ' ' + if start_time <= pkg.installtime: + nr = '*' + name = ps_info['name'] + cpu = int(ps_info['utime']) + int(ps_info['stime']) + cpu = "%d:%02d" % (cpu / 60, cpu % 60) + rss = format_number(int(ps_info['vmrss']) * 1024) + S = ps_info['state'] + print " %8d %-16.16s %8s %7sB %10s: %s%s" % (pid, name, + cpu, rss, S,nr, ago) + + rc = 0 + return rc, ['%s' % basecmd] + + def needTs(self, base, basecmd, extcmds): + return False + + +def config_hook(conduit): + ''' + Yum Plugin Config Hook: + And the 'ps' command. + ''' + conduit.registerCommand(PSCommand()) diff --git a/yum-utils.spec b/yum-utils.spec index 056c8e8..c68de0a 100644 --- a/yum-utils.spec +++ b/yum-utils.spec @@ -348,6 +348,16 @@ Requires: yum >= 3.2.22 When this plugin is installed it will automatically snapshot any filesystem that is touched by the packages in a yum update or yum remove. +%package -n yum-plugin-ps +Summary: Yum plugin to look at processes, with respect to packages +Group: System Environment/Base +Requires: yum >= 3.2.28 + +%description -n yum-plugin-ps +When this plugin is installed it adds the yum command "ps", which allows you +to see which running processes are accociated with which packages (and if they +need rebooting, or have updates, etc.) + %prep %setup -q @@ -382,6 +392,7 @@ plugins="\ show-leaves \ local \ fs-snapshot \ + ps \ " mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/yum/pluginconf.d/ $RPM_BUILD_ROOT/usr/lib/yum-plugins/ @@ -600,6 +611,11 @@ fi %{_mandir}/man1/yum-fs-snapshot.1.* %{_mandir}/man5/yum-fs-snapshot.conf.5.* +%files -n yum-plugin-ps +%defattr(-, root, root) +%config(noreplace) %{_sysconfdir}/yum/pluginconf.d/ps.conf +/usr/lib/yum-plugins/ps.* + %changelog * Sun Jun 6 2010 Tim Lauridsen - mark as 1.1.27 commit 4812344d2119f3137143df43785b7a084abf6e99 Author: James Antill Date: Tue Jun 22 01:00:38 2010 -0400 Allow "ps" plugin to work on much older yum versions diff --git a/plugins/ps/ps.py b/plugins/ps/ps.py index d58fc61..05aa887 100644 --- a/plugins/ps/ps.py +++ b/plugins/ps/ps.py @@ -36,6 +36,21 @@ import time requires_api_version = '2.5' plugin_type = (TYPE_INTERACTIVE,) +def _rpmdb_return_running_packages(self, return_pids=False): + """returns a list of yum installed package objects which own a file + that are currently running or in use.""" + pkgs = {} + for pid in misc.return_running_pids(): + for fn in misc.get_open_files(pid): + for pkg in self.searchFiles(fn): + if pkg not in pkgs: + pkgs[pkg] = set() + pkgs[pkg].add(pid) + + if return_pids: + return pkgs + return sorted(pkgs.keys()) + class PSCommand: def getNames(self): @@ -62,7 +77,8 @@ class PSCommand: elif extcmds and extcmds[0] == 'restarts': extcmds = extcmds[1:] - pkgs = base.rpmdb.return_running_packages(return_pids=True) + # Call base.rpmdb.return_running_packages() eventually. + pkgs = _rpmdb_return_running_packages(base.rpmdb, return_pids=True) ts = base.rpmdb.readOnlyTS() kern_pkgtup = misc.get_running_kernel_pkgtup(ts) kern_pkg = None diff --git a/yum-utils.spec b/yum-utils.spec index c68de0a..223b0eb 100644 --- a/yum-utils.spec +++ b/yum-utils.spec @@ -351,7 +351,7 @@ filesystem that is touched by the packages in a yum update or yum remove. %package -n yum-plugin-ps Summary: Yum plugin to look at processes, with respect to packages Group: System Environment/Base -Requires: yum >= 3.2.28 +Requires: yum >= 3.2.27 %description -n yum-plugin-ps When this plugin is installed it adds the yum command "ps", which allows you