Remove unused eventlet code
- Remove the `tacker.agent` package. Its only module, agent/linux/utils.py, is not referenced anywhere in tacker. - Remove `subprocess_popen()` from `tacker.common.utils`; the removed agent module was its only caller. The `subprocess` import it needed goes away with it. - Import `sleep()` used by the cooperative readers directly from the time module instead of the eventlet fallback. `time.sleep(0)` yields the GIL, so the readers still allow other threads to be scheduled between chunks. - Remove the GreenPool instantiated but never used by NfvoPlugin. Signed-off-by: Yasufumi Ogawa <yasufum.o@gmail.com> Change-Id: I408e264a271311a7fc7ea21e0b4873b80d92b064
This commit is contained in:
1 parent
dff234bdcb
commit
2315a0de13
8 files changed
+9
-267
No files matched your search
Whitespace-only changes.
Whitespace-only changes.
@@ -1,95 +0,0 @@
|
||||
# Copyright 2012 Locaweb.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from tacker._i18n import _
|
||||
from tacker.common import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def create_process(cmd, root_helper=None, addl_env=None,
|
||||
debuglog=True):
|
||||
"""Create a process object for the given command.
|
||||
|
||||
The return value will be a tuple of the process object and the
|
||||
list of command arguments used to create it.
|
||||
"""
|
||||
if root_helper:
|
||||
cmd = shlex.split(root_helper) + cmd
|
||||
cmd = map(str, cmd)
|
||||
|
||||
if debuglog:
|
||||
LOG.debug("Running command: %s", cmd)
|
||||
env = os.environ.copy()
|
||||
if addl_env:
|
||||
env.update(addl_env)
|
||||
|
||||
obj = utils.subprocess_popen(cmd, shell=False,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=env)
|
||||
|
||||
return obj, cmd
|
||||
|
||||
|
||||
def execute(cmd, root_helper=None, process_input=None, addl_env=None,
|
||||
check_exit_code=True, return_stderr=False, debuglog=True):
|
||||
# Note(gongysh) not use log_levels in config file because
|
||||
# some other codes that are not in a loop probably need the debug log
|
||||
try:
|
||||
obj, cmd = create_process(cmd, root_helper=root_helper,
|
||||
addl_env=addl_env, debuglog=debuglog)
|
||||
_stdout, _stderr = (process_input and
|
||||
obj.communicate(process_input) or
|
||||
obj.communicate())
|
||||
obj.stdin.close()
|
||||
m = _("\nCommand: %(cmd)s\nExit code: %(code)s\nStdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r") % {'cmd': cmd, 'code': obj.returncode,
|
||||
'stdout': _stdout, 'stderr': _stderr}
|
||||
if obj.returncode:
|
||||
LOG.error(m)
|
||||
if check_exit_code:
|
||||
raise RuntimeError(m)
|
||||
elif debuglog:
|
||||
LOG.debug(m)
|
||||
finally:
|
||||
time.sleep(0)
|
||||
|
||||
return return_stderr and (_stdout, _stderr) or _stdout
|
||||
|
||||
|
||||
def find_child_pids(pid):
|
||||
"""Retrieve a list of the pids of child processes of the given pid."""
|
||||
|
||||
try:
|
||||
raw_pids = execute(['ps', '--ppid', pid, '-o', 'pid='])
|
||||
except RuntimeError as e:
|
||||
# Unexpected errors are the responsibility of the caller
|
||||
with excutils.save_and_reraise_exception() as ctxt:
|
||||
# Exception has already been logged by execute
|
||||
no_children_found = 'Exit code: 1' in str(e)
|
||||
if no_children_found:
|
||||
ctxt.reraise = False
|
||||
return []
|
||||
return [x.strip() for x in raw_pids.split('\n') if x.strip()]
|
||||
+9
-20
@@ -26,8 +26,8 @@ import math
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
from time import sleep
|
||||
from urllib import parse as urlparse
|
||||
|
||||
import netaddr
|
||||
@@ -38,11 +38,6 @@ from oslo_utils import excutils
|
||||
from oslo_utils import importutils
|
||||
from stevedore import driver
|
||||
|
||||
try:
|
||||
from eventlet import sleep
|
||||
except ImportError:
|
||||
from time import sleep
|
||||
|
||||
from tacker._i18n import _
|
||||
from tacker.common import constants as q_const
|
||||
from tacker.common import exceptions
|
||||
@@ -143,12 +138,6 @@ def find_config_file(options, config_file):
|
||||
return cfg_file
|
||||
|
||||
|
||||
def subprocess_popen(args, stdin=None, stdout=None, stderr=None, shell=False,
|
||||
env=None):
|
||||
return subprocess.Popen(args, shell=shell, stdin=stdin, stdout=stdout,
|
||||
stderr=stderr, close_fds=True, env=env)
|
||||
|
||||
|
||||
def get_hostname():
|
||||
return socket.gethostname()
|
||||
|
||||
@@ -282,10 +271,10 @@ def expects_func_args(*args):
|
||||
|
||||
|
||||
def cooperative_iter(iter):
|
||||
"""Prevent eventlet thread starvation during iteration
|
||||
"""Prevent thread starvation during iteration
|
||||
|
||||
Return an iterator which schedules after each
|
||||
iteration. This can prevent eventlet thread starvation.
|
||||
iteration. This can prevent thread starvation.
|
||||
|
||||
:param iter: an iterator to wrap
|
||||
"""
|
||||
@@ -300,10 +289,10 @@ def cooperative_iter(iter):
|
||||
|
||||
|
||||
def cooperative_read(fd):
|
||||
"""Prevent eventlet thread starvationafter each read operation.
|
||||
"""Prevent thread starvation after each read operation.
|
||||
|
||||
Wrap a file descriptor's read with a partial function which schedules
|
||||
after each read. This can prevent eventlet thread starvation.
|
||||
after each read. This can prevent thread starvation.
|
||||
|
||||
:param fd: a file descriptor to wrap
|
||||
"""
|
||||
@@ -502,13 +491,13 @@ def json_merge_patch(target, patch):
|
||||
|
||||
|
||||
class CooperativeReader(object):
|
||||
"""An eventlet thread friendly class for reading in image data.
|
||||
"""A thread friendly class for reading in image data.
|
||||
|
||||
When accessing data either through the iterator or the read method
|
||||
we perform a sleep to allow a co-operative yield. When there is more than
|
||||
one image being uploaded/downloaded this prevents eventlet thread
|
||||
starvation, ie allows all threads to be scheduled periodically rather than
|
||||
having the same thread be continuously active.
|
||||
one image being uploaded/downloaded this prevents thread starvation,
|
||||
ie allows all threads to be scheduled periodically rather than having
|
||||
the same thread be continuously active.
|
||||
"""
|
||||
def __init__(self, fd):
|
||||
"""Construct an CooperativeReader object.
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import copy
|
||||
|
||||
import eventlet
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
@@ -60,7 +59,6 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb):
|
||||
|
||||
def __init__(self):
|
||||
super(NfvoPlugin, self).__init__()
|
||||
self._pool = eventlet.GreenPool()
|
||||
self._vim_drivers = driver_manager.DriverManager(
|
||||
'tacker.nfvo.vim.drivers',
|
||||
cfg.CONF.nfvo_vim.vim_drivers)
|
||||
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -1,150 +0,0 @@
|
||||
# Copyright 2012, VMware, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import oslo_i18n
|
||||
|
||||
from tacker.agent.linux import utils
|
||||
from tacker.tests import base
|
||||
|
||||
|
||||
_marker = object()
|
||||
|
||||
|
||||
class AgentUtilsExecuteTest(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(AgentUtilsExecuteTest, self).setUp()
|
||||
self.test_file = self.get_temp_file_path('test_execute.tmp')
|
||||
open(self.test_file, 'w').close()
|
||||
self.process = mock.patch(
|
||||
'tacker.common.utils.subprocess.Popen'
|
||||
).start()
|
||||
self.process.return_value.returncode = 0
|
||||
self.mock_popen = self.process.return_value.communicate
|
||||
|
||||
def test_without_helper(self):
|
||||
expected = "%s\n" % self.test_file
|
||||
self.mock_popen.return_value = [expected, ""]
|
||||
result = utils.execute(["ls", self.test_file])
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
def test_with_helper(self):
|
||||
expected = "ls %s\n" % self.test_file
|
||||
self.mock_popen.return_value = [expected, ""]
|
||||
result = utils.execute(["ls", self.test_file], root_helper='echo')
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
def test_stderr_true(self):
|
||||
expected = "%s\n" % self.test_file
|
||||
self.mock_popen.return_value = [expected, ""]
|
||||
out = utils.execute(["ls", self.test_file], return_stderr=True)
|
||||
self.assertIsInstance(out, tuple)
|
||||
self.assertEqual(out, (expected, ""))
|
||||
|
||||
def test_check_exit_code(self):
|
||||
self.mock_popen.return_value = ["", ""]
|
||||
stdout = utils.execute(["ls", self.test_file[:-1]],
|
||||
check_exit_code=False)
|
||||
self.assertEqual("", stdout)
|
||||
|
||||
def test_execute_raises(self):
|
||||
self.mock_popen.side_effect = RuntimeError
|
||||
self.assertRaises(RuntimeError, utils.execute,
|
||||
["ls", self.test_file[:-1]])
|
||||
|
||||
def test_process_input(self):
|
||||
expected = "%s\n" % self.test_file[:-1]
|
||||
self.mock_popen.return_value = [expected, ""]
|
||||
result = utils.execute(["cat"], process_input="%s\n" %
|
||||
self.test_file[:-1])
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
def test_with_addl_env(self):
|
||||
expected = "%s\n" % self.test_file
|
||||
self.mock_popen.return_value = [expected, ""]
|
||||
result = utils.execute(["ls", self.test_file],
|
||||
addl_env={'foo': 'bar'})
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
def test_return_code_log_error_raise_runtime(self):
|
||||
self.mock_popen.return_value = ('', '')
|
||||
self.process.return_value.returncode = 1
|
||||
with mock.patch.object(utils, 'LOG') as log:
|
||||
self.assertRaises(RuntimeError, utils.execute,
|
||||
['ls'])
|
||||
self.assertTrue(log.error.called)
|
||||
|
||||
def test_return_code_log_error_no_raise_runtime(self):
|
||||
self.mock_popen.return_value = ('', '')
|
||||
self.process.return_value.returncode = 1
|
||||
with mock.patch.object(utils, 'LOG') as log:
|
||||
utils.execute(['ls'], check_exit_code=False)
|
||||
self.assertTrue(log.error.called)
|
||||
|
||||
def test_return_code_log_debug(self):
|
||||
self.mock_popen.return_value = ('', '')
|
||||
with mock.patch.object(utils, 'LOG') as log:
|
||||
utils.execute(['ls'])
|
||||
self.assertTrue(log.debug.called)
|
||||
|
||||
def test_return_code_log_error_change_locale(self):
|
||||
ja_output = 'std_out in Japanese'
|
||||
ja_error = 'std_err in Japanese'
|
||||
ja_message_out = oslo_i18n._message.Message(ja_output)
|
||||
ja_message_err = oslo_i18n._message.Message(ja_error)
|
||||
ja_translate_out = oslo_i18n._translate.translate(ja_message_out, 'ja')
|
||||
ja_translate_err = oslo_i18n._translate.translate(ja_message_err, 'ja')
|
||||
self.mock_popen.return_value = (ja_translate_out, ja_translate_err)
|
||||
self.process.return_value.returncode = 1
|
||||
|
||||
with mock.patch.object(utils, 'LOG') as log:
|
||||
utils.execute(['ls'], check_exit_code=False)
|
||||
self.assertIn(ja_translate_out, str(log.error.call_args_list))
|
||||
self.assertIn(ja_translate_err, str(log.error.call_args_list))
|
||||
|
||||
def test_return_code_raise_runtime_log_fail_as_error(self):
|
||||
self.mock_popen.return_value = ('', '')
|
||||
self.process.return_value.returncode = 1
|
||||
with mock.patch.object(utils, 'LOG') as log:
|
||||
self.assertRaises(RuntimeError, utils.execute,
|
||||
['ls'])
|
||||
self.assertTrue(log.error.called)
|
||||
|
||||
def test_encode_process_input(self):
|
||||
bytes_idata = bytes("%s\n" % self.test_file[:-1], 'utf-8')
|
||||
bytes_odata = bytes("%s\n" % self.test_file, 'utf-8')
|
||||
self.mock_popen.return_value = [bytes_odata, b'']
|
||||
result = utils.execute(['cat'], process_input=bytes_idata)
|
||||
self.mock_popen.assert_called_once_with(bytes_idata)
|
||||
self.assertEqual(bytes_odata, result)
|
||||
|
||||
def test_return_str_data(self):
|
||||
str_data = "%s\n" % self.test_file
|
||||
self.mock_popen.return_value = [str_data, '']
|
||||
result = utils.execute(['ls', self.test_file], return_stderr=True)
|
||||
self.assertEqual((str_data, ''), result)
|
||||
|
||||
|
||||
class AgentUtilsExecuteEncodeTest(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(AgentUtilsExecuteEncodeTest, self).setUp()
|
||||
self.test_file = self.get_temp_file_path('test_execute.tmp')
|
||||
open(self.test_file, 'w').close()
|
||||
|
||||
def test_decode_return_data(self):
|
||||
str_data = bytes("%s\n" % self.test_file, 'utf-8')
|
||||
result = utils.execute(['ls', self.test_file], return_stderr=True)
|
||||
self.assertEqual((str_data, bytes('', 'utf-8')), result)
|
||||
Reference in new issue
Block a user