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
This commit is contained in:
parent
b5e96c49bf
commit
8fd3e884c7
|
@ -13,6 +13,7 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import ctypes
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -38,6 +39,8 @@ LOG = logging.getLogger(__name__)
|
||||||
subprocess = eventlet.patcher.original('subprocess')
|
subprocess = eventlet.patcher.original('subprocess')
|
||||||
subprocess.threading = eventlet.patcher.original('threading')
|
subprocess.threading = eventlet.patcher.original('threading')
|
||||||
|
|
||||||
|
ERROR_KEY_DELETED = 0x03FA
|
||||||
|
|
||||||
|
|
||||||
def create_process(cmd, run_as_root=False, addl_env=None,
|
def create_process(cmd, run_as_root=False, addl_env=None,
|
||||||
tpool_proxy=True):
|
tpool_proxy=True):
|
||||||
|
@ -71,8 +74,16 @@ def _get_wmi_process(pid):
|
||||||
if not pid:
|
if not pid:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
conn = wmi.WMI()
|
try:
|
||||||
processes = conn.Win32_Process(ProcessId=pid)
|
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:
|
if processes:
|
||||||
return processes[0]
|
return processes[0]
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -26,6 +26,13 @@ from neutron.agent.windows import utils
|
||||||
from neutron.tests import base
|
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
|
@ddt.ddt
|
||||||
class WindowsUtilsTestCase(base.BaseTestCase):
|
class WindowsUtilsTestCase(base.BaseTestCase):
|
||||||
@mock.patch('os.environ', {mock.sentinel.key0: mock.sentinel.val0})
|
@mock.patch('os.environ', {mock.sentinel.key0: mock.sentinel.val0})
|
||||||
|
@ -87,6 +94,25 @@ class WindowsUtilsTestCase(base.BaseTestCase):
|
||||||
if pid:
|
if pid:
|
||||||
mock_conn.Win32_Process.assert_called_once_with(ProcessId=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)
|
@ddt.data(True, False)
|
||||||
@mock.patch.object(utils, '_get_wmi_process')
|
@mock.patch.object(utils, '_get_wmi_process')
|
||||||
def test_kill_process(self, process_exists, mock_get_process):
|
def test_kill_process(self, process_exists, mock_get_process):
|
||||||
|
|
Loading…
Reference in New Issue