windows: fix terminating processes
The neutron Windows exec call helper doesn't properly handle the
situation in which the process that it's trying to kill was already
terminated, in which case using wmi to fetch the process can raise
an exception.
This change ensures that those WMI exceptions will be properly
handled.
Closes-Bug: 1872663
Change-Id: I00c810fe541ac5e1e9923155fe90eb07a0b4b3dd
(cherry picked from commit 8fd3e884c7
)
This commit is contained in:
parent
5936e4cea9
commit
6d3bf74df1
|
@ -13,6 +13,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ctypes
|
||||
import io
|
||||
import os
|
||||
|
||||
|
@ -37,6 +38,8 @@ LOG = logging.getLogger(__name__)
|
|||
subprocess = eventlet.patcher.original('subprocess')
|
||||
subprocess.threading = eventlet.patcher.original('threading')
|
||||
|
||||
ERROR_KEY_DELETED = 0x03FA
|
||||
|
||||
|
||||
def create_process(cmd, run_as_root=False, addl_env=None,
|
||||
tpool_proxy=True):
|
||||
|
@ -70,8 +73,16 @@ def _get_wmi_process(pid):
|
|||
if not pid:
|
||||
return None
|
||||
|
||||
conn = wmi.WMI()
|
||||
processes = conn.Win32_Process(ProcessId=pid)
|
||||
try:
|
||||
conn = wmi.WMI()
|
||||
processes = conn.Win32_Process(ProcessId=pid)
|
||||
except wmi.x_wmi as exc:
|
||||
hresult = exc.com_error.hresult
|
||||
err_code = ctypes.c_uint(hresult).value & 0xFFFF
|
||||
if err_code == ERROR_KEY_DELETED:
|
||||
return None
|
||||
raise
|
||||
|
||||
if processes:
|
||||
return processes[0]
|
||||
return None
|
||||
|
|
|
@ -26,6 +26,13 @@ from neutron.common import exceptions
|
|||
from neutron.tests import base
|
||||
|
||||
|
||||
class x_wmi(Exception):
|
||||
def __init__(self, info='', com_error=None):
|
||||
super(x_wmi, self).__init__(info)
|
||||
self.info = info
|
||||
self.com_error = com_error
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class WindowsUtilsTestCase(base.BaseTestCase):
|
||||
@mock.patch('os.environ', {mock.sentinel.key0: mock.sentinel.val0})
|
||||
|
@ -87,6 +94,25 @@ class WindowsUtilsTestCase(base.BaseTestCase):
|
|||
if pid:
|
||||
mock_conn.Win32_Process.assert_called_once_with(ProcessId=pid)
|
||||
|
||||
@ddt.data({},
|
||||
{"hresult": 0xff,
|
||||
"expect_exc": True})
|
||||
@ddt.unpack
|
||||
@mock.patch.object(utils, 'wmi', create=True)
|
||||
def test_get_wmi_process_exc(self, mock_wmi, expect_exc=False,
|
||||
hresult=0x800703FA):
|
||||
mock_conn = mock_wmi.WMI.return_value
|
||||
mock_wmi.x_wmi = x_wmi
|
||||
com_error = mock.Mock(hresult=hresult)
|
||||
exc = x_wmi(com_error=com_error)
|
||||
mock_conn.Win32_Process.side_effect = exc
|
||||
|
||||
if expect_exc:
|
||||
self.assertRaises(
|
||||
x_wmi, utils._get_wmi_process, mock.sentinel.pid)
|
||||
else:
|
||||
self.assertIsNone(utils._get_wmi_process(mock.sentinel.pid))
|
||||
|
||||
@ddt.data(True, False)
|
||||
@mock.patch.object(utils, '_get_wmi_process')
|
||||
def test_kill_process(self, process_exists, mock_get_process):
|
||||
|
|
Loading…
Reference in New Issue