Separate deployments from tasks
The patch introduce deployments as independent operations. The command line interface supports of creation, deletion and recreation of deployments. The creation of the task requires the id of a deployment. The patch also separate samples of configuration to two types: a deployment and a task. Change-Id: I5121532057909040e6ab6d6b2cbd6d06812975cb Implements: blueprint independent-deploy
This commit is contained in:
parent
03d24ea307
commit
18aa88bca7
7
doc/samples/deployments/devstack-in-dummy.json
Normal file
7
doc/samples/deployments/devstack-in-dummy.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "DevstackEngine",
|
||||
"provider": {
|
||||
"name": "DummyProvider",
|
||||
"credentials": ["root@10.2.0.8"]
|
||||
}
|
||||
}
|
12
doc/samples/deployments/dummy.json
Normal file
12
doc/samples/deployments/dummy.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "DummyEngine",
|
||||
"cloud_config": {
|
||||
"identity": {
|
||||
"url": "http://example.net/",
|
||||
"uri": "http://example.net:5000/v2.0/",
|
||||
"admin_username": "admin",
|
||||
"admin_password": "myadminpass",
|
||||
"admin_tenant_name": "demo"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +1,12 @@
|
||||
{
|
||||
"deploy": {
|
||||
"name": "DummyEngine",
|
||||
"cloud_config": {
|
||||
"identity": {
|
||||
"url": "http://example.net/",
|
||||
"uri": "http://example.net:5000/v2.0/",
|
||||
"admin_username": "admin",
|
||||
"admin_password": "myadminpass",
|
||||
"admin_tenant_name": "demo"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"tests": {
|
||||
"verify": [],
|
||||
"benchmark": {
|
||||
"NovaServers.boot_and_delete_server": [
|
||||
{"args": {"flavor_id": 1,
|
||||
"image_id": "73257560-c59b-4275-a1ec-ab140e5b9979"},
|
||||
"execution": "continuous",
|
||||
"config": {"times": 10, "active_users": 2,
|
||||
"tenants": 3, "users_per_tenant": 2}}
|
||||
]
|
||||
}
|
||||
"verify": [],
|
||||
"benchmark": {
|
||||
"NovaServers.boot_and_delete_server": [
|
||||
{"args": {"flavor_id": 1,
|
||||
"image_id": "73257560-c59b-4275-a1ec-ab140e5b9979"},
|
||||
"execution": "continuous",
|
||||
"config": {"times": 10, "active_users": 2,
|
||||
"tenants": 3, "users_per_tenant": 2}}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,7 @@
|
||||
{
|
||||
"deploy": {
|
||||
"name": "DummyEngine",
|
||||
"cloud_config": {
|
||||
"identity": {
|
||||
"url": "http://example.net/",
|
||||
"uri": "http://example.net:5000/v2.0/",
|
||||
"admin_username": "admin",
|
||||
"admin_password": "myadminpass",
|
||||
"admin_tenant_name": "demo"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"tests": {
|
||||
"verify": [
|
||||
"sanity",
|
||||
"smoke"
|
||||
],
|
||||
"benchmark": {}
|
||||
}
|
||||
"verify": [
|
||||
"sanity",
|
||||
"smoke"
|
||||
],
|
||||
"benchmark": {}
|
||||
}
|
||||
|
@ -1,18 +1,4 @@
|
||||
{
|
||||
"deploy": {
|
||||
"name": "DummyEngine",
|
||||
"cloud_config": {
|
||||
"identity": {
|
||||
"url": "http://example.net/",
|
||||
"uri": "http://example.net:5000/v2.0/",
|
||||
"admin_username": "admin",
|
||||
"admin_password": "myadminpass",
|
||||
"admin_tenant_name": "demo"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"tests": {
|
||||
"verify": [],
|
||||
"benchmark": {
|
||||
"NovaServers.boot_and_bounce_server": [
|
||||
@ -22,5 +8,4 @@
|
||||
"config": {"times": 3, "active_users": 2}}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,18 +105,19 @@ class DeploymentCommands(object):
|
||||
|
||||
class TaskCommands(object):
|
||||
|
||||
# TODO(akscram): We should to specify an UUID of the deployment via
|
||||
# the --deploy-id argument.
|
||||
@cliutils.args('--deploy-id', type=str, dest='deploy_id', required=True,
|
||||
help='UUID of the deployment')
|
||||
@cliutils.args('--task',
|
||||
help='Path to the file with full configuration of task')
|
||||
def start(self, task):
|
||||
"""Run Benchmark task
|
||||
:param config: File with json configration
|
||||
Returns task_uuid
|
||||
def start(self, deploy_id, task):
|
||||
"""Run a benchmark task.
|
||||
|
||||
:param deploy_id: an UUID of a deployment
|
||||
:param config: a file with json configration
|
||||
"""
|
||||
with open(task) as task_file:
|
||||
config_dict = json.load(task_file)
|
||||
api.start_task(config_dict)
|
||||
api.start_task(deploy_id, config_dict)
|
||||
|
||||
@cliutils.args('--task-id', type=str, dest='task_id', help='UUID of task')
|
||||
def abort(self, task_id):
|
||||
|
@ -126,9 +126,7 @@ class Task(BASE, RallyBase):
|
||||
deployment_uuid = sa.Column(
|
||||
sa.String(36),
|
||||
sa.ForeignKey(Deployment.uuid),
|
||||
# TODO(akscram): We should to set nullable=False after
|
||||
# separation. It's True only for compatibility.
|
||||
nullable=True,
|
||||
nullable=False,
|
||||
)
|
||||
deployment = sa.orm.relationship(
|
||||
Deployment,
|
||||
|
@ -26,7 +26,12 @@ def create_deploy(config, name):
|
||||
:param config: a dict with deployment configuration
|
||||
:param name: a str represents a name of the deployment
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
deployment = objects.Deployment(name=name, config=config)
|
||||
deployer = deploy.EngineFactory.get_engine(deployment['config']['name'],
|
||||
deployment)
|
||||
with deployer:
|
||||
endpoint = deployer.make_deploy()
|
||||
deployment.update_endpoint(endpoint)
|
||||
|
||||
|
||||
def destroy_deploy(deploy_uuid):
|
||||
@ -34,7 +39,16 @@ def destroy_deploy(deploy_uuid):
|
||||
|
||||
:param deploy_uuid: UUID of the deployment
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
# TODO(akscram): We have to be sure that there are no running
|
||||
# tasks for this deployment.
|
||||
# TODO(akscram): Check that the deployment have got a status that
|
||||
# is equal to "*->finised" or "deploy->inconsistent".
|
||||
deployment = objects.Deployment.get(deploy_uuid)
|
||||
deployer = deploy.EngineFactory.get_engine(deployment['config']['name'],
|
||||
deployment)
|
||||
with deployer:
|
||||
deployer.make_cleanup()
|
||||
deployment.delete()
|
||||
|
||||
|
||||
def recreate_deploy(deploy_uuid):
|
||||
@ -42,38 +56,37 @@ def recreate_deploy(deploy_uuid):
|
||||
|
||||
:param deploy_uuid: UUID of the deployment
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
# TODO(akscram): The additional argument with the UUID of the
|
||||
# deployment.
|
||||
def start_task(config):
|
||||
"""Start Benchmark task.
|
||||
1) Deploy OpenStack Cloud
|
||||
2) Verify Deployment
|
||||
3) Run Benchmarks
|
||||
4) Process benchmark results
|
||||
5) Destroy cloud and cleanup
|
||||
Returns task uuid
|
||||
"""
|
||||
deploy_conf = config['deploy']
|
||||
benchmark_conf = config['tests']
|
||||
|
||||
deployment = objects.Deployment(config=deploy_conf)
|
||||
task = objects.Task(deployment_uuid=deployment['uuid'])
|
||||
|
||||
deployment = objects.Deployment.get(deploy_uuid)
|
||||
deployer = deploy.EngineFactory.get_engine(deployment['config']['name'],
|
||||
deployment)
|
||||
tester = engine.TestEngine(benchmark_conf, task)
|
||||
with deployer:
|
||||
deployer.make_cleanup()
|
||||
endpoint = deployer.make_deploy()
|
||||
deployment.update_endpoint(endpoint)
|
||||
|
||||
|
||||
def start_task(deploy_uuid, config):
|
||||
"""Start a task.
|
||||
|
||||
A task is performed in two stages: a verification of a deployment
|
||||
and a benchmark.
|
||||
|
||||
:param deploy_uuid: UUID of the deployment
|
||||
:param config: a dict with a task configuration
|
||||
"""
|
||||
deployment = objects.Deployment.get(deploy_uuid)
|
||||
task = objects.Task(deployment_uuid=deploy_uuid)
|
||||
|
||||
tester = engine.TestEngine(config, task)
|
||||
deployer = deploy.EngineFactory.get_engine(deployment['config']['name'],
|
||||
deployment)
|
||||
endpoint = deployment['endpoint']
|
||||
with deployer:
|
||||
with tester.bind(endpoint):
|
||||
# TODO(akscram): The verifications should be a part of
|
||||
# deployment.
|
||||
tester.verify()
|
||||
tester.benchmark()
|
||||
deployer.make_cleanup()
|
||||
# TODO(akscram): It's just to follow legacy logic.
|
||||
deployment.delete()
|
||||
|
||||
|
||||
def abort_task(task_uuid):
|
||||
|
@ -31,8 +31,9 @@ class TaskCommandsTestCase(test.BaseTestCase):
|
||||
mock.mock_open(read_data='{"some": "json"}'),
|
||||
create=True)
|
||||
def test_start(self, mock_api):
|
||||
self.task.start('path_to_config.json')
|
||||
mock_api.assert_called_once_with({'some': 'json'})
|
||||
deploy_id = str(uuid.uuid4())
|
||||
self.task.start(deploy_id, 'path_to_config.json')
|
||||
mock_api.assert_called_once_with(deploy_id, {'some': 'json'})
|
||||
|
||||
def test_abort(self):
|
||||
test_uuid = str(uuid.uuid4())
|
||||
|
@ -24,12 +24,18 @@ from rally import test
|
||||
|
||||
|
||||
class TasksTestCase(test.DBTestCase):
|
||||
def setUp(self):
|
||||
super(TasksTestCase, self).setUp()
|
||||
self.deploy = db.deployment_create({})
|
||||
|
||||
def _get_task(self, uuid):
|
||||
return db.task_get(uuid)
|
||||
|
||||
def _create_task(self, values=None):
|
||||
return db.task_create(values or {})
|
||||
values = values or {}
|
||||
if 'deployment_uuid' not in values:
|
||||
values['deployment_uuid'] = self.deploy['uuid']
|
||||
return db.task_create(values)
|
||||
|
||||
def test_task_get_not_found(self):
|
||||
self.assertRaises(exceptions.TaskNotFound,
|
||||
|
@ -72,6 +72,7 @@ class APITestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(APITestCase, self).setUp()
|
||||
self.deploy_config = FAKE_DEPLOY_CONFIG
|
||||
self.task_config = FAKE_TASK_CONFIG
|
||||
self.deploy_uuid = str(uuid.uuid4())
|
||||
self.endpoint = FAKE_DEPLOY_CONFIG['cloud_config']
|
||||
self.task_uuid = str(uuid.uuid4())
|
||||
@ -84,27 +85,19 @@ class APITestCase(test.TestCase):
|
||||
'config': self.deploy_config,
|
||||
'endpoint': self.endpoint,
|
||||
}
|
||||
self.full_config = {
|
||||
'deploy': FAKE_DEPLOY_CONFIG,
|
||||
'tests': FAKE_TASK_CONFIG,
|
||||
}
|
||||
|
||||
@mock.patch('rally.benchmark.engine.utils.ScenarioRunner')
|
||||
@mock.patch('rally.benchmark.engine.utils.Verifier')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_get')
|
||||
@mock.patch('rally.objects.task.db.task_result_create')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_delete')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_create')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_update')
|
||||
@mock.patch('rally.objects.task.db.task_update')
|
||||
@mock.patch('rally.objects.task.db.task_create')
|
||||
def test_start_task(self, mock_task_create, mock_task_update,
|
||||
mock_deploy_update, mock_deploy_create,
|
||||
mock_deploy_delete, mock_task_result_create,
|
||||
mock_task_result_create, mock_deploy_get,
|
||||
mock_utils_verifier, mock_utils_runner):
|
||||
mock_task_create.return_value = self.task
|
||||
mock_task_update.return_value = self.task
|
||||
mock_deploy_create.return_value = self.deployment
|
||||
mock_deploy_update.return_value = self.deployment
|
||||
mock_deploy_get.return_value = self.deployment
|
||||
|
||||
mock_utils_verifier.return_value = mock_verifier = mock.Mock()
|
||||
mock_utils_verifier.list_verification_tests.return_value = {
|
||||
@ -117,15 +110,9 @@ class APITestCase(test.TestCase):
|
||||
mock_utils_runner.return_value = mock_runner = mock.Mock()
|
||||
mock_runner.run.return_value = ['fake_result']
|
||||
|
||||
api.start_task(self.full_config)
|
||||
api.start_task(self.deploy_uuid, self.task_config)
|
||||
|
||||
mock_deploy_create.assert_called_once_with(
|
||||
{'config': self.deploy_config})
|
||||
mock_deploy_update.assert_has_calls([
|
||||
mock.call(self.deploy_uuid, {'status': 'deploy->started'}),
|
||||
mock.call(self.deploy_uuid, {'status': 'deploy->finished'}),
|
||||
mock.call(self.deploy_uuid, {'endpoint': self.endpoint}),
|
||||
])
|
||||
mock_deploy_get.assert_called_once_with(self.deploy_uuid)
|
||||
mock_task_create.assert_called_once_with({
|
||||
'deployment_uuid': self.deploy_uuid,
|
||||
})
|
||||
@ -159,8 +146,6 @@ class APITestCase(test.TestCase):
|
||||
'raw': ['fake_result'],
|
||||
},
|
||||
)
|
||||
# TODO(akscram): It's just to follow legacy logic.
|
||||
mock_deploy_delete.assert_called_once_with(self.deploy_uuid)
|
||||
|
||||
def test_abort_task(self):
|
||||
self.assertRaises(NotImplementedError, api.abort_task,
|
||||
@ -178,11 +163,37 @@ class APITestCase(test.TestCase):
|
||||
api.delete_task(self.task_uuid, force=True)
|
||||
mock_delete.assert_called_once_with(self.task_uuid, status=None)
|
||||
|
||||
def test_create_deploy(self):
|
||||
self.assertRaises(NotImplementedError, api.create_deploy, 'name', {})
|
||||
@mock.patch('rally.objects.deploy.db.deployment_update')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_create')
|
||||
def test_create_deploy(self, mock_create, mock_update):
|
||||
mock_create.return_value = self.deployment
|
||||
mock_update.return_value = self.deployment
|
||||
api.create_deploy(self.deploy_config, 'fake_deploy')
|
||||
mock_create.assert_called_once_with({
|
||||
'name': 'fake_deploy',
|
||||
'config': self.deploy_config,
|
||||
})
|
||||
mock_update.assert_has_calls([
|
||||
mock.call(self.deploy_uuid, {'endpoint': self.endpoint}),
|
||||
])
|
||||
|
||||
def test_destroy_deploy(self):
|
||||
self.assertRaises(NotImplementedError, api.destroy_deploy, 'uuid')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_delete')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_update')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_get')
|
||||
def test_destroy_deploy(self, mock_get, mock_update, mock_delete):
|
||||
mock_get.return_value = self.deployment
|
||||
mock_update.return_value = self.deployment
|
||||
api.destroy_deploy(self.deploy_uuid)
|
||||
mock_get.assert_called_once_with(self.deploy_uuid)
|
||||
mock_delete.assert_called_once_with(self.deploy_uuid)
|
||||
|
||||
def test_recreate_deploy(self):
|
||||
self.assertRaises(NotImplementedError, api.recreate_deploy, 'uuid')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_update')
|
||||
@mock.patch('rally.objects.deploy.db.deployment_get')
|
||||
def test_recreate_deploy(self, mock_get, mock_update):
|
||||
mock_get.return_value = self.deployment
|
||||
mock_update.return_value = self.deployment
|
||||
api.recreate_deploy(self.deploy_uuid)
|
||||
mock_get.assert_called_once_with(self.deploy_uuid)
|
||||
mock_update.assert_has_calls([
|
||||
mock.call(self.deploy_uuid, {'endpoint': self.endpoint}),
|
||||
])
|
||||
|
Loading…
x
Reference in New Issue
Block a user