Flow extension uses extension manager from agent

Removed creating separate extension manager for flow extension.
Instead, have made flow extension using the same extension manager
instance which is initialized in agent. It fixes circular
extension loading in stevedore.

Closes-Bug: #1316145
Change-Id: Id339f1876168a41ca43ba7473f3ff6949a233ef3
This commit is contained in:
Vladimir Kozhukalov
2014-05-05 13:57:04 +04:00
parent d69bd2b054
commit b306626e86
6 changed files with 24 additions and 37 deletions

View File

@@ -102,6 +102,11 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
def __init__(self, api_url, advertise_address, listen_address, def __init__(self, api_url, advertise_address, listen_address,
lookup_timeout, lookup_interval, driver_name): lookup_timeout, lookup_interval, driver_name):
super(IronicPythonAgent, self).__init__() super(IronicPythonAgent, self).__init__()
self.ext_mgr = extension.ExtensionManager(
namespace='ironic_python_agent.extensions',
invoke_on_load=True,
propagate_map_exceptions=True,
)
self.api_url = api_url self.api_url = api_url
self.driver_name = driver_name self.driver_name = driver_name
self.api_client = ironic_api_client.APIClient(self.api_url, self.api_client = ironic_api_client.APIClient(self.api_url,
@@ -121,13 +126,6 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
self.lookup_timeout = lookup_timeout self.lookup_timeout = lookup_timeout
self.lookup_interval = lookup_interval self.lookup_interval = lookup_interval
def get_extension_manager(self):
return extension.ExtensionManager(
namespace='ironic_python_agent.extensions',
invoke_on_load=True,
propagate_map_exceptions=True,
)
def get_status(self): def get_status(self):
"""Retrieve a serializable status.""" """Retrieve a serializable status."""
return IronicPythonAgentStatus( return IronicPythonAgentStatus(

View File

@@ -182,3 +182,7 @@ class SystemRebootError(RESTError):
super(SystemRebootError, self).__init__() super(SystemRebootError, self).__init__()
self.details = 'Reboot script failed with exit code {0}.' self.details = 'Reboot script failed with exit code {0}.'
self.details = self.details.format(exit_code) self.details = self.details.format(exit_code)
class ExtensionError(Exception):
pass

View File

@@ -131,11 +131,14 @@ class ExecuteCommandMixin(object):
def __init__(self): def __init__(self):
self.command_lock = threading.Lock() self.command_lock = threading.Lock()
self.command_results = utils.get_ordereddict() self.command_results = utils.get_ordereddict()
self.ext_mgr = self.get_extension_manager() self.ext_mgr = None
def get_extension_manager(self): def get_extension(self, extension_name):
raise NotImplementedError( if self.ext_mgr is None:
'get_extension_manager should be implemented in successor class') raise errors.ExtensionError('Extension manager is not initialized')
ext = self.ext_mgr[extension_name].obj
ext.ext_mgr = self.ext_mgr
return ext
def split_command(self, command_name): def split_command(self, command_name):
command_parts = command_name.split('.', 1) command_parts = command_name.split('.', 1)
@@ -156,7 +159,7 @@ class ExecuteCommandMixin(object):
raise errors.CommandExecutionError('agent is busy') raise errors.CommandExecutionError('agent is busy')
try: try:
ext = self.ext_mgr[extension_part].obj ext = self.get_extension(extension_part)
result = ext.execute(command_part, **kwargs) result = ext.execute(command_part, **kwargs)
except KeyError: except KeyError:
# Extension Not found # Extension Not found

View File

@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from stevedore import enabled
from ironic_python_agent import errors from ironic_python_agent import errors
from ironic_python_agent.extensions import base from ironic_python_agent.extensions import base
from ironic_python_agent.openstack.common import log from ironic_python_agent.openstack.common import log
@@ -21,11 +19,6 @@ from ironic_python_agent.openstack.common import log
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
def _load_extension(ext):
disabled_extension_list = ['flow']
return ext.name not in disabled_extension_list
def _validate_exts(ext, flow=None): def _validate_exts(ext, flow=None):
for task in flow: for task in flow:
for method in task: for method in task:
@@ -42,14 +35,6 @@ class FlowExtension(base.BaseAgentExtension, base.ExecuteCommandMixin):
super(FlowExtension, self).__init__() super(FlowExtension, self).__init__()
self.command_map['start_flow'] = self.start_flow self.command_map['start_flow'] = self.start_flow
def get_extension_manager(self):
return enabled.EnabledExtensionManager(
'ironic_python_agent.extensions',
_load_extension,
invoke_on_load=True,
propagate_map_exceptions=True,
)
@base.async_command(_validate_exts) @base.async_command(_validate_exts)
def start_flow(self, flow=None): def start_flow(self, flow=None):
for task in flow: for task in flow:

View File

@@ -125,15 +125,10 @@ class TestHeartbeater(test_base.BaseTestCase):
class TestBaseAgent(test_base.BaseTestCase): class TestBaseAgent(test_base.BaseTestCase):
@mock.patch.object(agent.IronicPythonAgent, 'get_extension_manager') def setUp(self):
def setUp(self, fake_ext_mgr):
super(TestBaseAgent, self).setUp() super(TestBaseAgent, self).setUp()
self.encoder = encoding.RESTJSONEncoder(indent=4) self.encoder = encoding.RESTJSONEncoder(indent=4)
fake_ext_mgr.return_value = extension.ExtensionManager.\
make_test_instance([extension.Extension('fake', None,
FakeExtension,
FakeExtension())])
self.agent = agent.IronicPythonAgent('https://fake_api.example.' self.agent = agent.IronicPythonAgent('https://fake_api.example.'
'org:8081/', 'org:8081/',
('203.0.113.1', 9990), ('203.0.113.1', 9990),
@@ -141,6 +136,10 @@ class TestBaseAgent(test_base.BaseTestCase):
300, 300,
1, 1,
'agent_ipmitool') 'agent_ipmitool')
self.agent.ext_mgr = extension.ExtensionManager.\
make_test_instance([extension.Extension('fake', None,
FakeExtension,
FakeExtension())])
def assertEqualEncoded(self, a, b): def assertEqualEncoded(self, a, b):
# Evidently JSONEncoder.default() can't handle None (??) so we have to # Evidently JSONEncoder.default() can't handle None (??) so we have to

View File

@@ -52,9 +52,7 @@ class FakeExtension(base.BaseAgentExtension):
class FakeAgent(base.ExecuteCommandMixin): class FakeAgent(base.ExecuteCommandMixin):
def __init__(self): def __init__(self):
super(FakeAgent, self).__init__() super(FakeAgent, self).__init__()
self.ext_mgr = extension.ExtensionManager.make_test_instance(
def get_extension_manager(self):
return extension.ExtensionManager.make_test_instance(
[extension.Extension('fake', None, FakeExtension, [extension.Extension('fake', None, FakeExtension,
FakeExtension())]) FakeExtension())])
@@ -88,7 +86,7 @@ class TestExecuteCommandMixin(test_base.BaseTestCase):
def test_execute_command_success(self): def test_execute_command_success(self):
expected_result = base.SyncCommandResult('fake', None, True, None) expected_result = base.SyncCommandResult('fake', None, True, None)
fake_ext = self.agent.ext_mgr['fake'].obj fake_ext = self.agent.get_extension('fake')
fake_ext.execute = mock.Mock() fake_ext.execute = mock.Mock()
fake_ext.execute.return_value = expected_result fake_ext.execute.return_value = expected_result
result = self.agent.execute_command('fake.sleep', result = self.agent.execute_command('fake.sleep',