Add task status tracking

Task state is storing in database and updating with db.api methods.
Task uuid is stored in self.task_uuid property of engine.
Added method `update_status' in base engine class.

Blueprint db-task-track

Change-Id: I34be803d3f0566e62321e064fdf46b37145348e0
This commit is contained in:
Sergey Skripnick 2013-09-17 17:57:04 +03:00
parent b4d0d04856
commit a6297b14ca
6 changed files with 139 additions and 18 deletions

1
.gitignore vendored
View File

@ -26,6 +26,7 @@ pip-log.txt
.tox .tox
nosetests.xml nosetests.xml
.testrepository .testrepository
*.sqlite
# Translations # Translations
*.mo *.mo

View File

@ -47,6 +47,7 @@ class _TaskStatus(_Immutable, _Enum):
REPO_TOOL_GETTING_REPOS = 'repo_tool->getting_repos' REPO_TOOL_GETTING_REPOS = 'repo_tool->getting_repos'
DEPLOY_STARTED = 'deploy->started'
DEPLOY_CREATING_VENV = 'deploy->create_venv_to_deploy_openstack' DEPLOY_CREATING_VENV = 'deploy->create_venv_to_deploy_openstack'
DEPLOY_BUILDING_OPENSTACK_IN_VENV = 'deploy->building_openstack_in_venv' DEPLOY_BUILDING_OPENSTACK_IN_VENV = 'deploy->building_openstack_in_venv'
DEPLOY_BUILDING_IMAGE = 'deploy->building_images_with_openstack' DEPLOY_BUILDING_IMAGE = 'deploy->building_images_with_openstack'

View File

@ -17,6 +17,8 @@
import abc import abc
from rally import consts
from rally import db
from rally import exceptions from rally import exceptions
from rally import utils from rally import utils
@ -49,11 +51,14 @@ class EngineFactory(object):
__metaclass__ = abc.ABCMeta __metaclass__ = abc.ABCMeta
@staticmethod @staticmethod
def get_engine(name, config): def get_engine(name, uuid, config):
"""Returns instance of deploy engine with corresponding name.""" """Returns instance of deploy engine with corresponding name."""
for engine in utils.itersubclasses(EngineFactory): for engine in utils.itersubclasses(EngineFactory):
if name == engine.__name__: if name == engine.__name__:
return engine(config) new_engine = engine(config)
new_engine.task_uuid = str(uuid)
db.task_create({'uuid': str(uuid)})
return new_engine
raise exceptions.NoSuchEngine(engine_name=name) raise exceptions.NoSuchEngine(engine_name=name)
@staticmethod @staticmethod
@ -69,8 +74,16 @@ class EngineFactory(object):
def cleanup(self): def cleanup(self):
"""Cleanup OpenStack deployment.""" """Cleanup OpenStack deployment."""
def update_status(self, status):
db.task_update(self.task_uuid, {'status': status})
def __enter__(self): def __enter__(self):
return self.deploy() self.update_status(consts.TaskStatus.DEPLOY_STARTED)
deploy = self.deploy()
self.update_status(consts.TaskStatus.DEPLOY_FINISHED)
return deploy
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):
self.update_status(consts.TaskStatus.CLEANUP)
self.cleanup() self.cleanup()
self.update_status(consts.TaskStatus.FINISHED)

View File

@ -17,6 +17,9 @@
"""Test for deploy engines.""" """Test for deploy engines."""
import mock
import uuid
from rally import deploy from rally import deploy
from rally import exceptions from rally import exceptions
from rally import test from rally import test
@ -26,11 +29,15 @@ class EngineFactoryTestCase(test.NoDBTestCase):
def test_get_engine_not_found(self): def test_get_engine_not_found(self):
self.assertRaises(exceptions.NoSuchEngine, self.assertRaises(exceptions.NoSuchEngine,
deploy.EngineFactory.get_engine, deploy.EngineFactory.get_engine, uuid.uuid4(),
"non_existing_engine", None) "non_existing_engine", None)
def _create_fake_engines(self): def _create_fake_engines(self):
class EngineMixIn(object): class EngineMixIn(object):
def __init__(self, config):
pass
def deploy(self): def deploy(self):
pass pass
@ -38,23 +45,23 @@ class EngineFactoryTestCase(test.NoDBTestCase):
pass pass
class EngineFake1(EngineMixIn, deploy.EngineFactory): class EngineFake1(EngineMixIn, deploy.EngineFactory):
def __init__(self, config):
pass pass
class EngineFake2(EngineMixIn, deploy.EngineFactory): class EngineFake2(EngineMixIn, deploy.EngineFactory):
def __init__(self, config):
pass pass
class EngineFake3(EngineFake2): class EngineFake3(EngineFake2):
def __init__(self, config):
pass pass
return [EngineFake1, EngineFake2, EngineFake3] return [EngineFake1, EngineFake2, EngineFake3]
def test_get_engine(self): def test_get_engine(self):
engines = self._create_fake_engines() engines = self._create_fake_engines()
with mock.patch('rally.deploy.engine.db'):
for e in engines: for e in engines:
engine_inst = deploy.EngineFactory.get_engine(e.__name__, None) engine_inst = deploy.EngineFactory.get_engine(e.__name__,
uuid.uuid4(),
{})
# TODO(boris-42): make it work through assertIsInstance # TODO(boris-42): make it work through assertIsInstance
self.assertEqual(str(type(engine_inst)), str(e)) self.assertEqual(str(type(engine_inst)), str(e))
@ -80,7 +87,9 @@ class EngineFactoryTestCase(test.NoDBTestCase):
def cleanup(self): def cleanup(self):
self.cleanuped = True self.cleanuped = True
with deploy.EngineFactory.get_engine('A', None) as deployment: with mock.patch('rally.deploy.engine.db'):
with deploy.EngineFactory.get_engine('A', uuid.uuid4(),
None) as deployment:
self.assertTrue(deployment.deployed) self.assertTrue(deployment.deployed)
self.assertTrue(deployment.cleanuped) self.assertTrue(deployment.cleanuped)

View File

@ -17,6 +17,9 @@
"""Test fake deploy engines.""" """Test fake deploy engines."""
import mock
import uuid
from rally import deploy from rally import deploy
from rally.deploy.engines import fake_engine from rally.deploy.engines import fake_engine
from rally import test from rally import test
@ -40,5 +43,7 @@ class TestFakeDeployEngine(test.NoDBTestCase):
fake_engine.FakeEngine({}).cleanup() fake_engine.FakeEngine({}).cleanup()
def test_fake_engine_is_in_factory(self): def test_fake_engine_is_in_factory(self):
engine = deploy.EngineFactory.get_engine('FakeEngine', {}) with mock.patch('rally.db'):
engine = deploy.EngineFactory.get_engine('FakeEngine',
uuid.uuid4(), {})
self.assertIsInstance(engine, fake_engine.FakeEngine) self.assertIsInstance(engine, fake_engine.FakeEngine)

View File

@ -0,0 +1,92 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013: Mirantis Inc.
# 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.
"""Test task status update."""
import mock
import uuid
from rally import consts
from rally import deploy
from rally import test
class FakeFailure(Exception):
pass
class EngineFailedDeploy(deploy.engines.fake_engine.FakeEngine):
def deploy(self):
raise FakeFailure('fake deploy failed')
class EngineFailedCleanup(deploy.engines.fake_engine.FakeEngine):
def cleanup(self):
raise FakeFailure('fake deploy failed')
get_engine = deploy.EngineFactory.get_engine
class TaskStatusTestCase(test.NoDBTestCase):
def test_task_status_basic_chain(self):
task_uuid = str(uuid.uuid4())
with mock.patch('rally.deploy.engine.db') as mock_obj:
with get_engine('FakeEngine', task_uuid, {}):
pass
s = consts.TaskStatus
expected = [
mock.call.task_create({'uuid': task_uuid}),
mock.call.task_update(task_uuid, {'status': s.DEPLOY_STARTED}),
mock.call.task_update(task_uuid, {'status': s.DEPLOY_FINISHED}),
mock.call.task_update(task_uuid, {'status': s.CLEANUP}),
mock.call.task_update(task_uuid, {'status': s.FINISHED}),
]
self.assertEqual(mock_obj.mock_calls, expected)
def _test_failure(self, task_uuid, engine, expected_calls):
with mock.patch('rally.deploy.engine.db') as mock_obj:
engine = get_engine(engine, task_uuid, {})
try:
with engine:
pass
except FakeFailure:
pass
self.assertEqual(mock_obj.mock_calls, expected_calls)
def test_task_status_failed_deploy(self):
task_uuid = str(uuid.uuid4())
s = consts.TaskStatus
expected = [
mock.call.task_create({'uuid': task_uuid}),
mock.call.task_update(task_uuid, {'status': s.DEPLOY_STARTED}),
]
self._test_failure(task_uuid, 'EngineFailedDeploy', expected)
def test_task_status_failed_cleanup(self):
task_uuid = str(uuid.uuid4())
s = consts.TaskStatus
expected = [
mock.call.task_create({'uuid': task_uuid}),
mock.call.task_update(task_uuid, {'status': s.DEPLOY_STARTED}),
mock.call.task_update(task_uuid, {'status': s.DEPLOY_FINISHED}),
mock.call.task_update(task_uuid, {'status': s.CLEANUP}),
]
self._test_failure(task_uuid, 'EngineFailedCleanup', expected)