Merge pull request #14032 from ihrwein/add-partial-psutil-2.0-compatibility-to-ps-module

ps: add partial psutil 2.0 compatibility
This commit is contained in:
Thomas S Hatch 2014-07-09 12:39:35 -06:00
commit 23abbb99b3
2 changed files with 100 additions and 25 deletions

View File

@ -18,7 +18,9 @@ from salt.exceptions import SaltInvocationError
# Import third party libs
try:
import psutil
HAS_PSUTIL = True
PSUTIL2 = psutil.version_info >= (2, 0)
except ImportError:
HAS_PSUTIL = False
@ -39,6 +41,60 @@ def __virtual__():
return False
def _get_proc_cmdline(proc):
'''
Returns the cmdline of a Process instance.
It's backward compatible with < 2.0 versions of psutil.
'''
return proc.cmdline() if PSUTIL2 else proc.cmdline
def _get_proc_create_time(proc):
'''
Returns the create_time of a Process instance.
It's backward compatible with < 2.0 versions of psutil.
'''
return proc.create_time() if PSUTIL2 else proc.create_time
def _get_proc_name(proc):
'''
Returns the name of a Process instance.
It's backward compatible with < 2.0 versions of psutil.
'''
return proc.name() if PSUTIL2 else proc.name
def _get_proc_status(proc):
'''
Returns the status of a Process instance.
It's backward compatible with < 2.0 versions of psutil.
'''
return proc.status() if PSUTIL2 else proc.status
def _get_proc_username(proc):
'''
Returns the username of a Process instance.
It's backward compatible with < 2.0 versions of psutil.
'''
return proc.username() if PSUTIL2 else proc.username
def _get_proc_pid(proc):
'''
Returns the pid of a Process instance.
It's backward compatible with < 2.0 versions of psutil.
'''
return proc.pid() if PSUTIL2 else proc.pid
def top(num_processes=5, interval=3):
'''
Return a list of top CPU consuming processes during the interval.
@ -76,18 +132,18 @@ def top(num_processes=5, interval=3):
for idx, (diff, process) in enumerate(reversed(sorted(usage))):
if num_processes and idx >= num_processes:
break
if len(process.cmdline) == 0:
cmdline = [process.name]
if len(_get_proc_cmdline(process)) == 0:
cmdline = [_get_proc_name(process)]
else:
cmdline = process.cmdline
cmdline = _get_proc_cmdline(process)
info = {'cmd': cmdline,
'user': process.username,
'status': process.status,
'pid': process.pid,
'create_time': process.create_time,
'user': _get_proc_username(process),
'status': _get_proc_status(process),
'pid': _get_proc_pid(process),
'create_time': _get_proc_create_time(process),
'cpu': {},
'mem': {},
}
}
for key, value in process.get_cpu_times()._asdict().items():
info['cpu'][key] = value
for key, value in process.get_memory_info()._asdict().items():
@ -180,13 +236,13 @@ def pkill(pattern, user=None, signal=15, full=False):
killed = []
for proc in psutil.process_iter():
name_match = pattern in ' '.join(proc.cmdline) if full \
else pattern in proc.name
user_match = True if user is None else user == proc.username
name_match = pattern in ' '.join(_get_proc_cmdline(proc)) if full \
else pattern in _get_proc_name(proc)
user_match = True if user is None else user == _get_proc_username(proc)
if name_match and user_match:
try:
proc.send_signal(signal)
killed.append(proc.pid)
killed.append(_get_proc_pid(proc))
except psutil.NoSuchProcess:
pass
if not killed:
@ -233,11 +289,11 @@ def pgrep(pattern, user=None, full=False):
procs = []
for proc in psutil.process_iter():
name_match = pattern in ' '.join(proc.cmdline) if full \
else pattern in proc.name
user_match = True if user is None else user == proc.username
name_match = pattern in ' '.join(_get_proc_cmdline(proc)) if full \
else pattern in _get_proc_name(proc)
user_match = True if user is None else user == _get_proc_username(proc)
if name_match and user_match:
procs.append(proc.pid)
procs.append(_get_proc_pid(proc))
return procs or None
@ -589,6 +645,7 @@ def get_users():
# try utmp
try:
import utmp
result = []
while True:
rec = utmp.utmpaccess.getutent()
@ -602,8 +659,9 @@ def get_users():
'started': started, 'host': rec[5]})
except ImportError:
return False
# This is a possible last ditch method
# result = []
# result = []
# w = __salt__['cmd.run'](
# 'who', env='{"LC_ALL": "en_US.UTF-8"}').splitlines()
# for u in w:

View File

@ -6,7 +6,7 @@
# Import Salt Testing libs
from salttesting import TestCase, skipIf
from salttesting.helpers import ensure_in_syspath
from salttesting.mock import MagicMock, patch, call
from salttesting.mock import MagicMock, patch, call, Mock
ensure_in_syspath('../../')
@ -17,6 +17,8 @@ HAS_PSUTIL = ps.__virtual__()
if HAS_PSUTIL:
import psutil
PSUTIL2 = psutil.version_info >= (2, 0)
STUB_CPU_TIMES = psutil._compat.namedtuple('cputimes', 'user nice system idle')(1, 2, 3, 4)
STUB_VIRT_MEM = psutil._compat.namedtuple('vmem', 'total available percent used free')(1000, 500, 50, 500, 500)
STUB_SWAP_MEM = psutil._compat.namedtuple('swap', 'total used free percent sin sout')(1000, 500, 500, 50, 0, 0)
@ -55,11 +57,23 @@ except ImportError:
HAS_UTMP = False
def _get_proc_name(proc):
return proc.name() if PSUTIL2 else proc.name
def _get_proc_pid(proc):
return proc.pid() if PSUTIL2 else proc.pid
@skipIf(not HAS_PSUTIL, "psutils are required for this test case")
class PsTestCase(TestCase):
def setUp(self):
MOCK_PROC.name = 'test_mock_proc'
MOCK_PROC.pid = 9999999999
if PSUTIL2:
MOCK_PROC.name = Mock(return_value="test_mock_proc")
MOCK_PROC.pid = Mock(return_value=9999999999)
else:
MOCK_PROC.name = 'test_mock_proc'
MOCK_PROC.pid = 9999999999
@patch('psutil.get_pid_list', new=MagicMock(return_value=STUB_PID_LIST))
def test_get_pid_list(self):
@ -75,12 +89,12 @@ class PsTestCase(TestCase):
def test_pkill(self, send_signal_mock):
mocked_proc.send_signal = MagicMock()
test_signal = 1234
ps.pkill(mocked_proc.name, signal=test_signal)
ps.pkill(_get_proc_name(mocked_proc), signal=test_signal)
self.assertEqual(mocked_proc.send_signal.call_args, call(test_signal))
@patch('psutil.process_iter', new=MagicMock(return_value=[MOCK_PROC]))
def test_pgrep(self):
self.assertIn(MOCK_PROC.pid, ps.pgrep(MOCK_PROC.name))
self.assertIn(_get_proc_pid(MOCK_PROC), ps.pgrep(_get_proc_name(MOCK_PROC)))
@patch('psutil.cpu_percent', new=MagicMock(return_value=1))
def test_cpu_percent(self):
@ -92,11 +106,13 @@ class PsTestCase(TestCase):
@patch('psutil.virtual_memory', new=MagicMock(return_value=STUB_VIRT_MEM))
def test_virtual_memory(self):
self.assertDictEqual({'used': 500, 'total': 1000, 'available': 500, 'percent': 50, 'free': 500}, ps.virtual_memory())
self.assertDictEqual({'used': 500, 'total': 1000, 'available': 500, 'percent': 50, 'free': 500},
ps.virtual_memory())
@patch('psutil.swap_memory', new=MagicMock(return_value=STUB_SWAP_MEM))
def test_swap_memory(self):
self.assertDictEqual({'used': 500, 'total': 1000, 'percent': 50, 'free': 500, 'sin': 0, 'sout': 0}, ps.swap_memory())
self.assertDictEqual({'used': 500, 'total': 1000, 'percent': 50, 'free': 500, 'sin': 0, 'sout': 0},
ps.swap_memory())
@patch('psutil.phymem_usage', new=MagicMock(return_value=STUB_PHY_MEM_USAGE))
def test_physical_memory_usage(self):
@ -108,7 +124,7 @@ class PsTestCase(TestCase):
# ps.cached_physical_memory is deprecated! See #9301
# def test_cached_physical_memory(self):
# pass
# pass
#ps.physical_memory_buffers is deprecated! See #9301
# def test_physical_memory_buffers(self):
@ -169,4 +185,5 @@ class PsTestCase(TestCase):
if __name__ == '__main__':
from integration import run_tests
run_tests(PsTestCase, needs_daemon=False)