Merge "Support alias for execution creation"
This commit is contained in:
commit
527474fe30
@ -23,6 +23,7 @@ from qinling.api.controllers.v1 import resources
|
||||
from qinling.api.controllers.v1 import types
|
||||
from qinling import context
|
||||
from qinling.db import api as db_api
|
||||
from qinling import exceptions as exc
|
||||
from qinling import rpc
|
||||
from qinling.utils import executions
|
||||
from qinling.utils import rest_utils
|
||||
@ -60,6 +61,11 @@ class ExecutionsController(rest.RestController):
|
||||
acl.enforce('execution:create', ctx)
|
||||
|
||||
params = body.to_dict()
|
||||
if not (params.get("function_id") or params.get("function_alias")):
|
||||
raise exc.InputException(
|
||||
'Either function_alias or function_id must be provided.'
|
||||
)
|
||||
|
||||
LOG.info("Creating %s. [params=%s]", self.type, params)
|
||||
|
||||
db_model = executions.create_execution(self.engine_client, params)
|
||||
|
@ -294,8 +294,9 @@ class RuntimePool(Resource):
|
||||
|
||||
class Execution(Resource):
|
||||
id = types.uuid
|
||||
function_id = wsme.wsattr(types.uuid, mandatory=True)
|
||||
function_id = wsme.wsattr(types.uuid)
|
||||
function_version = wsme.wsattr(int, default=0)
|
||||
function_alias = wtypes.text
|
||||
description = wtypes.text
|
||||
status = wsme.wsattr(wtypes.text, readonly=True)
|
||||
sync = bool
|
||||
|
@ -58,6 +58,39 @@ class TestExecutionController(base.APITest):
|
||||
resp = self.app.get('/v1/functions/%s/versions/1' % self.func_id)
|
||||
self.assertEqual(1, resp.json.get('count'))
|
||||
|
||||
@mock.patch('qinling.rpc.EngineClient.create_execution')
|
||||
def test_post_with_alias(self, mock_rpc):
|
||||
db_api.increase_function_version(self.func_id, 0,
|
||||
description="version 1")
|
||||
name = self.rand_name(name="alias", prefix=self.prefix)
|
||||
body = {
|
||||
'function_id': self.func_id,
|
||||
'function_version': 1,
|
||||
'name': name
|
||||
}
|
||||
db_api.create_function_alias(**body)
|
||||
|
||||
execution_body = {
|
||||
'function_alias': name
|
||||
}
|
||||
resp = self.app.post_json('/v1/executions', execution_body)
|
||||
self.assertEqual(201, resp.status_int)
|
||||
|
||||
resp = self.app.get('/v1/functions/%s' % self.func_id)
|
||||
self.assertEqual(0, resp.json.get('count'))
|
||||
|
||||
resp = self.app.get('/v1/functions/%s/versions/1' % self.func_id)
|
||||
self.assertEqual(1, resp.json.get('count'))
|
||||
|
||||
def test_post_without_required_params(self):
|
||||
resp = self.app.post(
|
||||
'/v1/executions',
|
||||
params={},
|
||||
expect_errors=True
|
||||
)
|
||||
|
||||
self.assertEqual(400, resp.status_int)
|
||||
|
||||
@mock.patch('qinling.rpc.EngineClient.create_execution')
|
||||
def test_post_rpc_error(self, mock_create_execution):
|
||||
mock_create_execution.side_effect = exc.QinlingException
|
||||
|
@ -70,10 +70,18 @@ def _update_function_version_db(version_id, pre_count):
|
||||
|
||||
|
||||
def create_execution(engine_client, params):
|
||||
function_id = params['function_id']
|
||||
function_alias = params.get('function_alias')
|
||||
function_id = params.get('function_id')
|
||||
version = params.get('function_version', 0)
|
||||
is_sync = params.get('sync', True)
|
||||
input = params.get('input')
|
||||
version = params.get('function_version', 0)
|
||||
|
||||
if function_alias:
|
||||
alias_db = db_api.get_function_alias(function_alias)
|
||||
function_id = alias_db.function_id
|
||||
version = alias_db.function_version
|
||||
params.update({'function_id': function_id,
|
||||
'version': version})
|
||||
|
||||
func_db = db_api.get_function(function_id)
|
||||
runtime_id = func_db.runtime_id
|
||||
|
@ -127,13 +127,29 @@ class QinlingClient(client_base.QinlingClientBase):
|
||||
|
||||
return self.post(url, None, headers={})
|
||||
|
||||
def create_execution(self, function_id, input=None, sync=True, version=0):
|
||||
req_body = {
|
||||
'function_id': function_id,
|
||||
'function_version': version,
|
||||
'sync': sync,
|
||||
'input': input
|
||||
}
|
||||
def create_execution(self, function_id=None, alias_name=None, input=None,
|
||||
sync=True, version=0):
|
||||
"""Create execution.
|
||||
|
||||
alias_name takes precedence over function_id.
|
||||
"""
|
||||
if alias_name:
|
||||
req_body = {
|
||||
'function_alias': alias_name,
|
||||
'sync': sync,
|
||||
'input': input
|
||||
}
|
||||
elif function_id:
|
||||
req_body = {
|
||||
'function_id': function_id,
|
||||
'function_version': version,
|
||||
'sync': sync,
|
||||
'input': input
|
||||
}
|
||||
else:
|
||||
raise Exception("Either alias_name or function_id must be "
|
||||
"provided.")
|
||||
|
||||
resp, body = self.post_json('executions', req_body)
|
||||
|
||||
return resp, body
|
||||
@ -208,3 +224,46 @@ class QinlingClient(client_base.QinlingClientBase):
|
||||
)
|
||||
|
||||
return resp, json.loads(body)
|
||||
|
||||
def create_function_alias(self, name, function_id,
|
||||
function_version=0, description=None):
|
||||
req_body = {
|
||||
'function_id': function_id,
|
||||
'function_version': function_version,
|
||||
'name': name
|
||||
}
|
||||
if description is not None:
|
||||
req_body['description'] = description
|
||||
|
||||
resp, body = self.post_json('/aliases', req_body)
|
||||
|
||||
return resp, body
|
||||
|
||||
def delete_function_alias(self, alias_name, ignore_notfound=False):
|
||||
try:
|
||||
resp, _ = self.delete('/v1/aliases/%s' % alias_name)
|
||||
return resp
|
||||
except exceptions.NotFound:
|
||||
if ignore_notfound:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
def get_function_alias(self, alias_name):
|
||||
resp, body = self.get('/v1/aliases/%s' % alias_name)
|
||||
|
||||
return resp, json.loads(body)
|
||||
|
||||
def update_function_alias(self, alias_name, function_id=None,
|
||||
function_version=None, description=None):
|
||||
req_body = {}
|
||||
if function_id is not None:
|
||||
req_body['function_id'] = function_id
|
||||
if function_version is not None:
|
||||
req_body['function_version'] = function_version
|
||||
if description is not None:
|
||||
req_body['description'] = description
|
||||
|
||||
resp, body = self.put_json('/v1/aliases/%s' % alias_name, req_body)
|
||||
|
||||
return resp, body
|
||||
|
@ -121,6 +121,32 @@ class ExecutionsTest(base.BaseQinlingTest):
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertNotIn('Hello, World', body)
|
||||
|
||||
@decorators.idempotent_id('dbf4bd84-bde3-4d1d-8dec-93aaf18b4b5f')
|
||||
def test_create_with_function_alias(self):
|
||||
function_id = self.create_function()
|
||||
|
||||
alias_name = self.create_function_alias(function_id)
|
||||
execution_id = self.create_execution(alias_name=alias_name)
|
||||
resp, body = self.client.get_execution_log(execution_id)
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertIn('Hello, World', body)
|
||||
|
||||
version_1 = self.create_function_version(function_id)
|
||||
alias_name_1 = self.create_function_alias(function_id, version_1)
|
||||
execution_id = self.create_execution(alias_name=alias_name_1)
|
||||
resp, body = self.client.get_execution_log(execution_id)
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertIn('Hello, World', body)
|
||||
|
||||
self.update_function_package(function_id,
|
||||
"python/test_python_sleep.py")
|
||||
version_2 = self.create_function_version(function_id)
|
||||
alias_name_2 = self.create_function_alias(function_id, version_2)
|
||||
execution_id = self.create_execution(alias_name=alias_name_2)
|
||||
resp, body = self.client.get_execution_log(execution_id)
|
||||
self.assertEqual(200, resp.status)
|
||||
self.assertNotIn('Hello, World', body)
|
||||
|
||||
@decorators.idempotent_id('8096cc52-64d2-4660-a657-9ac0bdd743ae')
|
||||
def test_execution_async(self):
|
||||
function_id = self.create_function()
|
||||
|
@ -213,9 +213,15 @@ class BaseQinlingTest(test.BaseTestCase):
|
||||
|
||||
return version
|
||||
|
||||
def create_execution(self, function_id, version=0, input=None):
|
||||
resp, body = self.client.create_execution(function_id, version=version,
|
||||
input=input)
|
||||
def create_execution(self, function_id=None, alias_name=None, version=0,
|
||||
input=None):
|
||||
if alias_name:
|
||||
resp, body = self.client.create_execution(alias_name=alias_name,
|
||||
input=input)
|
||||
else:
|
||||
resp, body = self.client.create_execution(function_id,
|
||||
version=version,
|
||||
input=input)
|
||||
|
||||
self.assertEqual(201, resp.status)
|
||||
|
||||
@ -226,3 +232,20 @@ class BaseQinlingTest(test.BaseTestCase):
|
||||
self.assertEqual('success', body['status'])
|
||||
|
||||
return execution_id
|
||||
|
||||
def create_function_alias(self, function_id=None, function_version=0):
|
||||
name = data_utils.rand_name(name="alias", prefix=self.name_prefix)
|
||||
if not function_id:
|
||||
function_id = self.create_function()
|
||||
|
||||
resp, body = self.client.create_function_alias(name,
|
||||
function_id,
|
||||
function_version)
|
||||
|
||||
self.assertEqual(201, resp.status)
|
||||
|
||||
alias_name = body['name']
|
||||
self.addCleanup(self.client.delete_function_alias, alias_name,
|
||||
ignore_notfound=True)
|
||||
|
||||
return alias_name
|
||||
|
Loading…
Reference in New Issue
Block a user