Add project_id to API resources

Currently our API doesn't return any project info in many resources, like
execution, cron-trigger, workbook, etc. As a essential property in those
resources, it's really helpful for users to process resources if we
return project_id in resource endpoints.

Closes-Bug: 1707573
Closes-Bug: 1694398

Change-Id: I866d20cf1f5129b6249140063aa0836f63626767
This commit is contained in:
int32bit 2017-08-22 14:22:30 +08:00
parent 1a8837b9d2
commit 2018962568
9 changed files with 103 additions and 0 deletions

View File

@ -33,6 +33,7 @@ class Workbook(resource.Resource):
tags = [wtypes.text]
scope = SCOPE_TYPES
"'private' or 'public'"
project_id = wsme.wsattr(wtypes.text, readonly=True)
created_at = wtypes.text
updated_at = wtypes.text
@ -45,6 +46,7 @@ class Workbook(resource.Resource):
'WORKBOOK DEFINITION IN MISTRAL DSL v2',
tags=['large', 'expensive'],
scope='private',
project_id='a7eb669e9819420ea4bd1453e672c0a7',
created_at='1970-01-01T00:00:00.000000',
updated_at='1970-01-01T00:00:00.000000')
@ -167,6 +169,7 @@ class Action(resource.Resource):
tags = [wtypes.text]
definition = wtypes.text
scope = SCOPE_TYPES
project_id = wsme.wsattr(wtypes.text, readonly=True)
created_at = wtypes.text
updated_at = wtypes.text
@ -179,6 +182,7 @@ class Action(resource.Resource):
definition='HERE GOES ACTION DEFINITION IN MISTRAL DSL v2',
tags=['large', 'expensive'],
scope='private',
project_id='a7eb669e9819420ea4bd1453e672c0a7',
created_at='1970-01-01T00:00:00.000000',
updated_at='1970-01-01T00:00:00.000000'
)
@ -252,6 +256,8 @@ class Execution(resource.Resource):
created_at = wtypes.text
updated_at = wtypes.text
project_id = wsme.wsattr(wtypes.text, readonly=True)
@classmethod
def sample(cls):
return cls(id='123e4567-e89b-12d3-a456-426655440000',
@ -259,6 +265,7 @@ class Execution(resource.Resource):
workflow_namespace='some_namespace',
workflow_id='123e4567-e89b-12d3-a456-426655441111',
description='this is the first execution.',
project_id='40a908dbddfe48ad80a87fb30fa70a03',
state='SUCCESS',
input={},
output={},
@ -309,6 +316,8 @@ class Task(resource.Resource):
state_info = wtypes.text
"an optional state information string"
project_id = wsme.wsattr(wtypes.text, readonly=True)
runtime_context = types.jsontype
result = wtypes.text
@ -332,6 +341,7 @@ class Task(resource.Resource):
workflow_execution_id='123e4567-e89b-12d3-a456-426655440000',
name='task',
state=states.SUCCESS,
project_id='40a908dbddfe48ad80a87fb30fa70a03',
runtime_context={
'triggered_by': [
{
@ -380,6 +390,7 @@ class ActionExecution(resource.Resource):
tags = [wtypes.text]
name = wtypes.text
description = wtypes.text
project_id = wsme.wsattr(wtypes.text, readonly=True)
accepted = bool
input = types.jsontype
output = types.jsontype
@ -400,6 +411,7 @@ class ActionExecution(resource.Resource):
tags=['foo', 'fee'],
name='std.echo',
description='My running action',
project_id='40a908dbddfe48ad80a87fb30fa70a03',
accepted=True,
input={'first_name': 'John', 'last_name': 'Doe'},
output={'some_output': 'Hello, John Doe!'},
@ -433,6 +445,7 @@ class CronTrigger(resource.Resource):
workflow_id = wtypes.text
workflow_input = types.jsontype
workflow_params = types.jsontype
project_id = wsme.wsattr(wtypes.text, readonly=True)
scope = SCOPE_TYPES
@ -453,6 +466,7 @@ class CronTrigger(resource.Resource):
workflow_id='123e4567-e89b-12d3-a456-426655441111',
workflow_input={},
workflow_params={},
project_id='40a908dbddfe48ad80a87fb30fa70a03',
scope='private',
pattern='* * * * *',
remaining_executions=42,
@ -484,6 +498,7 @@ class Environment(resource.Resource):
description = wtypes.text
variables = types.jsontype
scope = SCOPE_TYPES
project_id = wsme.wsattr(wtypes.text, readonly=True)
created_at = wtypes.text
updated_at = wtypes.text
@ -500,6 +515,7 @@ class Environment(resource.Resource):
'verbose': True
},
scope='private',
project_id='40a908dbddfe48ad80a87fb30fa70a03',
created_at='1970-01-01T00:00:00.000000',
updated_at='1970-01-01T00:00:00.000000'
)

View File

@ -206,6 +206,9 @@ MOCK_EMPTY = mock.MagicMock(return_value=[])
MOCK_NOT_FOUND = mock.MagicMock(side_effect=exc.DBEntityNotFoundError())
MOCK_DELETE = mock.MagicMock(return_value=None)
ACTION_EX_DB_WITH_PROJECT_ID = AD_HOC_ACTION_EX_DB.get_clone()
ACTION_EX_DB_WITH_PROJECT_ID.project_id = '<default-project>'
@mock.patch.object(rpc_base, '_IMPL_CLIENT', mock.Mock())
class TestActionExecutionsController(base.APITest):
@ -236,6 +239,14 @@ class TestActionExecutionsController(base.APITest):
self.assertEqual(404, resp.status_int)
@mock.patch.object(db_api, 'get_action_execution',
return_value=ACTION_EX_DB_WITH_PROJECT_ID)
def test_get_within_project_id(self, mock_get):
resp = self.app.get('/v2/action_executions/123')
self.assertEqual(200, resp.status_int)
self.assertTrue('project_id' in resp.json)
@mock.patch.object(rpc_clients.EngineClient, 'start_action')
def test_post(self, f):
f.return_value = ACTION_EX_DB.to_dict()

View File

@ -95,6 +95,9 @@ ACTION_DB.update(ACTION)
SYSTEM_ACTION_DB = models.ActionDefinition()
SYSTEM_ACTION_DB.update(SYSTEM_ACTION)
PROJECT_ID_ACTION_DB = ACTION_DB.get_clone()
PROJECT_ID_ACTION_DB.project_id = '<default-project>'
UPDATED_ACTION_DEFINITION = """
---
version: '2.0'
@ -155,6 +158,14 @@ class TestActionsController(base.APITest):
self.assertEqual(404, resp.status_int)
@mock.patch.object(
db_api, "get_action_definition", return_value=PROJECT_ID_ACTION_DB)
def test_get_within_project_id(self, mock_get):
url = '/v2/actions/1234'
resp = self.app.get(url, expect_errors=True)
self.assertEqual(200, resp.status_int)
self.assertTrue('project_id' in resp.json)
@mock.patch.object(
db_api, "get_action_definition", MOCK_ACTION)
@mock.patch.object(

View File

@ -57,6 +57,8 @@ trigger_values['workflow_params'] = json.loads(
TRIGGER_DB = models.CronTrigger()
TRIGGER_DB.update(trigger_values)
TRIGGER_DB_WITH_PROJECT_ID = TRIGGER_DB.get_clone()
TRIGGER_DB_WITH_PROJECT_ID.project_id = '<default-project>'
MOCK_WF = mock.MagicMock(return_value=WF)
MOCK_TRIGGER = mock.MagicMock(return_value=TRIGGER_DB)
@ -75,6 +77,14 @@ class TestCronTriggerController(base.APITest):
self.assertEqual(200, resp.status_int)
self.assertDictEqual(TRIGGER, resp.json)
@mock.patch.object(db_api, "get_cron_trigger",
return_value=TRIGGER_DB_WITH_PROJECT_ID)
def test_get_within_project_id(self, mock_get):
resp = self.app.get('/v2/cron_triggers/my_cron_trigger')
self.assertEqual(200, resp.status_int)
self.assertTrue('project_id' in resp.json)
@mock.patch.object(db_api, "get_cron_trigger", MOCK_NOT_FOUND)
def test_get_not_found(self):
resp = self.app.get(

View File

@ -66,6 +66,7 @@ ENVIRONMENT = {
'description': 'my test settings',
'variables': VARIABLES,
'scope': 'private',
'project_id': '<default-project>',
'created_at': str(datetime.datetime.utcnow()),
'updated_at': str(datetime.datetime.utcnow())
}
@ -85,12 +86,16 @@ ENVIRONMENT_DB = db.Environment(
description=ENVIRONMENT['description'],
variables=copy.deepcopy(VARIABLES),
scope=ENVIRONMENT['scope'],
project_id=ENVIRONMENT['project_id'],
created_at=datetime.datetime.strptime(ENVIRONMENT['created_at'],
DATETIME_FORMAT),
updated_at=datetime.datetime.strptime(ENVIRONMENT['updated_at'],
DATETIME_FORMAT)
)
ENVIRONMENT_DB_WITH_PROJECT_ID = ENVIRONMENT_DB.get_clone()
ENVIRONMENT_DB_WITH_PROJECT_ID.project_id = '<default-project>'
ENVIRONMENT_DB_DICT = {k: v for k, v in ENVIRONMENT_DB.items()}
UPDATED_VARIABLES = copy.deepcopy(VARIABLES)
@ -168,6 +173,14 @@ class TestEnvironmentController(base.APITest):
self.assertEqual(200, resp.status_int)
self._assert_dict_equal(ENVIRONMENT, resp.json)
@mock.patch.object(db_api, 'get_environment',
return_value=ENVIRONMENT_DB_WITH_PROJECT_ID)
def test_get_within_project_id(self, mock_get):
resp = self.app.get('/v2/environments/123')
self.assertEqual(200, resp.status_int)
self.assertEqual('<default-project>', resp.json['project_id'])
@mock.patch.object(db_api, "get_environment", MOCK_NOT_FOUND)
def test_get_not_found(self):
resp = self.app.get('/v2/environments/123', expect_errors=True)

View File

@ -121,6 +121,8 @@ UPDATED_WF_EX_ENV_DESC['params'] = {'env': {'k1': 'def'}}
WF_EX_JSON_WITH_DESC = copy.deepcopy(WF_EX_JSON)
WF_EX_JSON_WITH_DESC['description'] = WF_EX.description
WF_EX_WITH_PROJECT_ID = WF_EX.get_clone()
WF_EX_WITH_PROJECT_ID.project_id = '<default-project>'
MOCK_WF_EX = mock.MagicMock(return_value=WF_EX)
MOCK_SUB_WF_EX = mock.MagicMock(return_value=SUB_WF_EX)
@ -154,6 +156,13 @@ class TestExecutionsController(base.APITest):
self.assertEqual(404, resp.status_int)
@mock.patch.object(db_api, 'get_workflow_execution',
return_value=WF_EX_WITH_PROJECT_ID)
def test_get_within_project_id(self, mock_get):
resp = self.app.get('/v2/executions/123', expect_errors=True)
self.assertEqual(200, resp.status_int)
self.assertTrue('project_id' in resp.json)
@mock.patch.object(
db_api,
'ensure_workflow_execution_exists',

View File

@ -143,6 +143,9 @@ MOCK_NOT_FOUND = mock.MagicMock(side_effect=exc.DBEntityNotFoundError())
MOCK_ERROR_TASK = mock.MagicMock(return_value=ERROR_TASK_EX)
MOCK_ERROR_ITEMS_TASK = mock.MagicMock(return_value=ERROR_ITEMS_TASK_EX)
TASK_EX_WITH_PROJECT_ID = TASK_EX.get_clone()
TASK_EX_WITH_PROJECT_ID.project_id = '<default-project>'
@mock.patch.object(
data_flow,
@ -171,6 +174,14 @@ class TestTasksController(base.APITest):
self.assertEqual(1, len(resp.json['tasks']))
self.assertDictEqual(TASK_WITHOUT_RESULT, resp.json['tasks'][0])
@mock.patch.object(db_api, 'get_task_execution',
return_value=TASK_EX_WITH_PROJECT_ID)
def test_get_within_project_id(self, mock_get):
resp = self.app.get('/v2/tasks/123')
self.assertEqual(200, resp.status_int)
self.assertTrue('project_id' in resp.json)
@mock.patch.object(db_api, 'get_task_executions', MOCK_EMPTY)
def test_get_all_empty(self):
resp = self.app.get('/v2/tasks')

View File

@ -55,6 +55,9 @@ WORKBOOK = {
'updated_at': '1970-01-01 00:00:00'
}
WORKBOOK_DB_PROJECT_ID = WORKBOOK_DB.get_clone()
WORKBOOK_DB_PROJECT_ID.project_id = '<default-project>'
UPDATED_WORKBOOK_DB = copy.copy(WORKBOOK_DB)
UPDATED_WORKBOOK_DB['definition'] = UPDATED_WORKBOOK_DEF
UPDATED_WORKBOOK = copy.deepcopy(WORKBOOK)
@ -115,6 +118,14 @@ class TestWorkbooksController(base.APITest):
self.assertEqual(404, resp.status_int)
@mock.patch.object(db_api, "get_workbook",
return_value=WORKBOOK_DB_PROJECT_ID)
def test_get_within_project_id(self, mock_get):
resp = self.app.get('/v2/workbooks/123')
self.assertEqual(200, resp.status_int)
self.assertTrue('project_id' in resp.json)
@mock.patch.object(workbooks, "update_workbook_v2", MOCK_UPDATED_WORKBOOK)
def test_put(self):
resp = self.app.put(

View File

@ -111,6 +111,9 @@ WF_WITH_DEFAULT_INPUT = {
'input': 'param1, param2=2'
}
WF_DB_PROJECT_ID = WF_DB.get_clone()
WF_DB_PROJECT_ID.project_id = '<default-project>'
UPDATED_WF_DEFINITION = """
---
version: '2.0'
@ -666,3 +669,11 @@ class TestWorkflowsController(base.APITest):
namespace='abc'
)
self.assertDictEqual(WF_WITH_NAMESPACE, resp.json)
@mock.patch.object(db_api, "get_workflow_definition")
def test_workflow_within_project_id(self, mock_get):
mock_get.return_value = WF_DB_PROJECT_ID
resp = self.app.get(
'/v2/workflows/123e4567-e89b-12d3-a456-426655440000')
self.assertEqual(200, resp.status_int)
self.assertTrue('project_id' in resp.json)