Allows fetching of deployments from all environments.

Adds new endpoint /deployments to Murano, to enable
Murano Dashboard to get all deployments for all environments.
This is needed in order to improve log browsing for
deployments, which calls for creating a new view in which
all deployments across all environments can be viewed.

Also made deployment unit tests more robust.

Partially-implements: blueprint improve-deployment-log-browsing
Change-Id: I1b6a313af1a0c4aa57bd4e6f51da92b396b35165
This commit is contained in:
Felipe Monteiro 2017-01-05 11:41:16 -05:00
parent e9fa1114bf
commit c30c27fb0c
6 changed files with 184 additions and 16 deletions

View File

@ -679,6 +679,9 @@ Returns information about all deployments of the specified environment.
+==========+====================================+======================================+
| GET | /environments/<env_id>/deployments | Get list of environment deployments |
+----------+------------------------------------+--------------------------------------+
| GET | /deployments | Get list of deployments for all |
| | | environments in user's project |
+----------+---------------------------------------------------------------------------+
*Response*

View File

@ -16,6 +16,7 @@
"add_category": "rule:admin_api",
"list_deployments": "rule:default",
"list_deployments_all_environments": "rule:default",
"statuses_deployments": "rule:default",
"list_environments": "rule:default",

View File

@ -14,6 +14,7 @@
from oslo_log import log as logging
from sqlalchemy import desc
from sqlalchemy.orm import load_only
from webob import exc
from murano.api.v1 import request_statistics
@ -24,7 +25,7 @@ from murano.common import utils
from murano.common import wsgi
from murano.db import models
from murano.db import session as db_session
from murano.utils import verify_env
from murano.utils import check_env
LOG = logging.getLogger(__name__)
@ -33,18 +34,41 @@ API_NAME = 'Deployments'
class Controller(object):
@request_statistics.stats_count(API_NAME, 'Index')
@verify_env
def index(self, request, environment_id):
def index(self, request, environment_id=None):
all_environments = environment_id is None
LOG.debug('Deployments:List <all_environments: {0}>'
.format(all_environments))
if all_environments:
policy.check("list_deployments_all_environments", request.context)
else:
check_env(request, environment_id)
target = {"environment_id": environment_id}
policy.check("list_deployments", request.context, target)
unit = db_session.get_session()
if all_environments:
query = unit.query(models.Environment) \
.options(load_only('tenant_id')) \
.filter_by(tenant_id=request.context.tenant) \
.join(models.Task) \
.order_by(desc(models.Task.created))
result = query.all()
# The join statement above fetches the deployments into
# Environment.tasks. Iterate over that to get the deployments.
deployments = []
for row in result:
for deployment in row.tasks:
deployment = set_dep_state(deployment, unit).to_dict()
deployments.append(deployment)
else:
query = unit.query(models.Task) \
.filter_by(environment_id=environment_id) \
.order_by(desc(models.Task.created))
result = query.all()
deployments = [set_dep_state(deployment, unit).to_dict() for deployment
in result]
deployments = [set_dep_state(deployment, unit).to_dict()
for deployment in result]
return {'deployments': deployments}
@request_statistics.stats_count(API_NAME, 'Statuses')

View File

@ -168,6 +168,10 @@ class API(wsgi.Router):
controller=deployments_resource,
action='statuses',
conditions={'method': ['GET']})
mapper.connect('/deployments',
controller=deployments_resource,
action='index',
conditions={'method': ['GET']})
sessions_resource = sessions.create_resource()
mapper.connect('/environments/{environment_id}/configure',

View File

@ -39,25 +39,156 @@ class TestDeploymentsApi(tb.ControllerTest, tb.MuranoApiTestCase):
{'create_environment': '@',
'list_deployments': '@'}
)
self.expect_policy_check('create_environment')
# Create environment
# Create an environment.
self.expect_policy_check('create_environment')
request = self._post(
'/environments',
jsonutils.dump_as_bytes({'name': 'test_environment_1'}),
**CREDENTIALS
)
response_body = jsonutils.loads(request.get_response(self.api).body)
self.assertEqual(CREDENTIALS['tenant'],
response_body['tenant_id'])
self.assertEqual(CREDENTIALS['tenant'], response_body['tenant_id'])
self.assertEqual('test_environment_1', response_body['name'])
ENVIRONMENT_ID = response_body['id']
# Verify that the environment has not yet been deployed.
self.expect_policy_check('list_deployments',
{'environment_id': ENVIRONMENT_ID})
result = self.deployments_controller.index(request, ENVIRONMENT_ID)
self.assertEqual([], result['deployments'])
# Deploy the environment.
request = self._post('/environments/{environment_id}/configure'
.format(environment_id=ENVIRONMENT_ID),
b'', **CREDENTIALS)
response_body = jsonutils.loads(request.get_response(self.api).body)
SESSION_ID = response_body['id']
request = self._post('/environments/{environment_id}/sessions/'
'{session_id}/deploy'
.format(environment_id=ENVIRONMENT_ID,
session_id=SESSION_ID),
b'', **CREDENTIALS)
result = request.get_response(self.api)
self.assertEqual('200 OK', result.status)
# Verify that the environment was deployed.
self.expect_policy_check('list_deployments',
{'environment_id': ENVIRONMENT_ID})
result = self.deployments_controller.index(request, ENVIRONMENT_ID)
deployment_id = result['deployments'][0]['id']
self.assertEqual(1, len(result['deployments']))
self.assertIsNotNone(deployment_id)
def test_deployments_all_environments(self):
"""Test list deployments for all environments.
Create 2 environments, deploy both, and check that 2 deployments exist.
"""
CREDENTIALS = {'tenant': 'test_tenant_1', 'user': 'test_user_1'}
self._set_policy_rules(
{'create_environment': '@',
'list_deployments_all_environments': '@'}
)
for count in range(2):
# Create environment.
self.expect_policy_check('create_environment')
request = self._post(
'/environments',
jsonutils.dump_as_bytes(
{'name': 'test_environment_{0}'.format(count)}),
**CREDENTIALS
)
response_body = jsonutils.loads(
request.get_response(self.api).body)
self.assertEqual(CREDENTIALS['tenant'], response_body['tenant_id'])
self.assertEqual('test_environment_{0}'.format(count),
response_body['name'])
ENVIRONMENT_ID = response_body['id']
# Deploy environment.
request = self._post('/environments/{environment_id}/configure'
.format(environment_id=ENVIRONMENT_ID),
b'', **CREDENTIALS)
response_body = jsonutils.loads(
request.get_response(self.api).body)
SESSION_ID = response_body['id']
request = self._post('/environments/{environment_id}/sessions/'
'{session_id}/deploy'
.format(environment_id=ENVIRONMENT_ID,
session_id=SESSION_ID),
b'', **CREDENTIALS)
result = request.get_response(self.api)
self.assertEqual('200 OK', result.status)
# Check that 2 deployments exist.
self.expect_policy_check('list_deployments_all_environments')
result = self.deployments_controller.index(request, None)
self.assertEqual(2, len(result['deployments']))
for deployment in result['deployments']:
self.assertIsNotNone(deployment)
self.assertNotEqual(result['deployments'][0], result['deployments'][1])
def test_deployments_all_environments_different_tenants(self):
"""Test list deployments for all environments in different tenants.
Should only return return environments for current tenant.
"""
CREDENTIALS = {'tenant': 'test_tenant_1', 'user': 'test_user_1'}
ALT_CREDENTIALS = {'tenant': 'test_tenant_2', 'user': 'test_user_2'}
self._set_policy_rules(
{'create_environment': '@',
'list_deployments_all_environments': '@'}
)
deployments = []
# Create the first environment inside first tenant and the second
# environments inside the alternate tenant. Then deploy both.
for count, creds in enumerate([CREDENTIALS, ALT_CREDENTIALS]):
# Create each environment.
self.expect_policy_check('create_environment')
request = self._post(
'/environments',
jsonutils.dump_as_bytes(
{'name': 'test_environment_{0}'.format(count)}),
**creds
)
response_body = jsonutils.loads(
request.get_response(self.api).body)
self.assertEqual(creds['tenant'], response_body['tenant_id'])
self.assertEqual('test_environment_{0}'.format(count),
response_body['name'])
ENVIRONMENT_ID = response_body['id']
# Deploy each environment.
request = self._post('/environments/{environment_id}/configure'
.format(environment_id=ENVIRONMENT_ID),
b'', **creds)
response_body = jsonutils.loads(
request.get_response(self.api).body)
SESSION_ID = response_body['id']
request = self._post('/environments/{environment_id}/sessions/'
'{session_id}/deploy'
.format(environment_id=ENVIRONMENT_ID,
session_id=SESSION_ID),
b'', **creds)
result = request.get_response(self.api)
self.assertEqual('200 OK', result.status)
# Check that each tenant only returns one deployment.
self.expect_policy_check('list_deployments_all_environments')
result = self.deployments_controller.index(request, None)
self.assertEqual(1, len(result['deployments']))
deployment_id = result['deployments'][0]['id']
self.assertIsNotNone(deployment_id)
deployments.append(deployment_id)
self.assertNotEqual(deployments[0], deployments[1])
def test_deployments_not_found_statuses(self):
CREDENTIALS = {'tenant': 'test_tenant_1', 'user': 'test_user_1'}
self._set_policy_rules(

View File

@ -0,0 +1,5 @@
---
features:
- It is now possible to make a GET request to '/deployments' endpoint.
This will result in deployments for all environments in a specific project
(tenant) being returned.