Skip to content

Commit

Permalink
Merge pull request #50839 from terminalmage/issue50829
Browse files Browse the repository at this point in the history
Fix UnicodeDecodeError in ps module
  • Loading branch information
dwoz authored Dec 12, 2018
2 parents 264a042 + 3a3d9b7 commit 14d7d1d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 17 deletions.
13 changes: 7 additions & 6 deletions salt/modules/ps.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import re

# Import salt libs
import salt.utils.data
from salt.exceptions import SaltInvocationError, CommandExecutionError

# Import third party libs
Expand Down Expand Up @@ -53,9 +54,9 @@ def _get_proc_cmdline(proc):
It's backward compatible with < 2.0 versions of psutil.
'''
try:
return proc.cmdline() if PSUTIL2 else proc.cmdline
return salt.utils.data.decode(proc.cmdline() if PSUTIL2 else proc.cmdline)
except (psutil.NoSuchProcess, psutil.AccessDenied):
return ''
return []


def _get_proc_create_time(proc):
Expand All @@ -65,7 +66,7 @@ def _get_proc_create_time(proc):
It's backward compatible with < 2.0 versions of psutil.
'''
try:
return proc.create_time() if PSUTIL2 else proc.create_time
return salt.utils.data.decode(proc.create_time() if PSUTIL2 else proc.create_time)
except (psutil.NoSuchProcess, psutil.AccessDenied):
return None

Expand All @@ -77,7 +78,7 @@ def _get_proc_name(proc):
It's backward compatible with < 2.0 versions of psutil.
'''
try:
return proc.name() if PSUTIL2 else proc.name
return salt.utils.data.decode(proc.name() if PSUTIL2 else proc.name)
except (psutil.NoSuchProcess, psutil.AccessDenied):
return []

Expand All @@ -89,7 +90,7 @@ def _get_proc_status(proc):
It's backward compatible with < 2.0 versions of psutil.
'''
try:
return proc.status() if PSUTIL2 else proc.status
return salt.utils.data.decode(proc.status() if PSUTIL2 else proc.status)
except (psutil.NoSuchProcess, psutil.AccessDenied):
return None

Expand All @@ -101,7 +102,7 @@ def _get_proc_username(proc):
It's backward compatible with < 2.0 versions of psutil.
'''
try:
return proc.username() if PSUTIL2 else proc.username
return salt.utils.data.decode(proc.username() if PSUTIL2 else proc.username)
except (psutil.NoSuchProcess, psutil.AccessDenied, KeyError):
return None

Expand Down
61 changes: 50 additions & 11 deletions tests/unit/modules/test_ps.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
# Import Python libs
from __future__ import absolute_import, unicode_literals, print_function
from collections import namedtuple
import time

# Import Salt Testing libs
from tests.support.unit import TestCase, skipIf
from tests.support.mock import MagicMock, patch, call, Mock

# Import Salt libs
import salt.utils.data
import salt.modules.ps as ps

HAS_PSUTIL_VERSION = False
Expand Down Expand Up @@ -63,6 +65,48 @@ def _get_proc_pid(proc):
return proc.pid


class DummyProcess(object):
'''
Dummy class to emulate psutil.Process. This ensures that _any_ string
values used for any of the options passed in are converted to str types on
both Python 2 and Python 3.
'''
def __init__(self, cmdline=None, create_time=None, name=None, status=None,
username=None, pid=None):
self._cmdline = salt.utils.data.decode(
cmdline if cmdline is not None else [],
to_str=True)
self._create_time = salt.utils.data.decode(
create_time if create_time is not None else time.time(),
to_str=True)
self._name = salt.utils.data.decode(
name if name is not None else [],
to_str=True)
self._status = salt.utils.data.decode(status, to_str=True)
self._username = salt.utils.data.decode(username, to_str=True)
self._pid = salt.utils.data.decode(
pid if pid is not None else 12345,
to_str=True)

def cmdline(self):
return self._cmdline

def create_time(self):
return self._create_time

def name(self):
return self._name

def status(self):
return self._status

def username(self):
return self._username

def pid(self):
return self._pid


class PsTestCase(TestCase):
def setUp(self):
self.mocked_proc = mocked_proc = MagicMock('salt.utils.psutil_compat.Process')
Expand All @@ -73,6 +117,12 @@ def setUp(self):
self.mocked_proc.name = 'test_mock_proc'
self.mocked_proc.pid = 9999999999

@skipIf(not ps.PSUTIL2, 'Only run for psutil 2.x')
def test__get_proc_cmdline(self):
cmdline = ['echo', 'питон']
ret = ps._get_proc_cmdline(DummyProcess(cmdline=cmdline))
assert ret == cmdline, ret

def test_get_pid_list(self):
with patch('salt.utils.psutil_compat.pids',
MagicMock(return_value=STUB_PID_LIST)):
Expand Down Expand Up @@ -142,17 +192,6 @@ def test_disk_partition_usage(self):
'fstype': 'hfs'},
ps.disk_partitions()[0])

## Should only be tested in integration
# def test_total_physical_memory(self):
# pass

## Should only be tested in integration
# def test_num_cpus(self):
# pass

## Should only be tested in integration
# def test_boot_time(self):
# pass
def test_network_io_counters(self):
with patch('salt.utils.psutil_compat.net_io_counters',
MagicMock(return_value=STUB_NETWORK_IO)):
Expand Down

0 comments on commit 14d7d1d

Please sign in to comment.