Validate swift params for swift type function creation

Check the swift related params before sending request to Swift.

Change-Id: I29866eeb95f8b6e465d781ed02d2d499413dff54
Story: 2003482
Task: 24882
This commit is contained in:
Lingxian Kong 2018-08-29 11:21:04 +12:00
parent 5f7ba972b6
commit ffbd3ba111
3 changed files with 134 additions and 13 deletions

View File

@ -201,8 +201,15 @@ class FunctionsController(rest.RestController):
data = kwargs['package'].file.read() data = kwargs['package'].file.read()
elif source == constants.SWIFT_FUNCTION: elif source == constants.SWIFT_FUNCTION:
swift_info = values['code'].get('swift', {}) swift_info = values['code'].get('swift', {})
self._check_swift(swift_info.get('container'),
swift_info.get('object')) if not (swift_info.get('container') and swift_info.get('object')):
raise exc.InputException("Both container and object must be "
"provided for swift type function.")
self._check_swift(
swift_info.get('container'),
swift_info.get('object')
)
else: else:
create_trust = False create_trust = False
values['entry'] = None values['entry'] = None
@ -341,11 +348,15 @@ class FunctionsController(rest.RestController):
when function is updating. when function is updating.
""" """
values = {} values = {}
for key in UPDATE_ALLOWED:
if kwargs.get(key) is not None: try:
if key == "code": for key in UPDATE_ALLOWED:
kwargs[key] = json.loads(kwargs[key]) if kwargs.get(key) is not None:
values.update({key: kwargs[key]}) if key == "code":
kwargs[key] = json.loads(kwargs[key])
values.update({key: kwargs[key]})
except Exception as e:
raise exc.InputException("Invalid input, %s" % str(e))
LOG.info('Update function %s, params: %s', id, values) LOG.info('Update function %s, params: %s', id, values)
ctx = context.get_ctx() ctx = context.get_ctx()
@ -416,10 +427,29 @@ class FunctionsController(rest.RestController):
values.pop('package') values.pop('package')
# Swift type function # Swift type function
if pre_source == constants.SWIFT_FUNCTION: if (pre_source == constants.SWIFT_FUNCTION and
swift_info = values['code'].get('swift', {}) "swift" in values.get('code', {})):
self._check_swift(swift_info.get('container'), swift_info = values['code']["swift"]
swift_info.get('object'))
if not (swift_info.get('container') or
swift_info.get('object')):
raise exc.InputException(
"Either container or object must be provided for "
"swift type function update."
)
new_swift_info = pre_func.code['swift']
new_swift_info.update(swift_info)
self._check_swift(
new_swift_info.get('container'),
new_swift_info.get('object')
)
values['code'] = {
"source": pre_source,
"swift": new_swift_info
}
# Delete allocated resources in orchestrator and etcd. # Delete allocated resources in orchestrator and etcd.
self.engine_client.delete_function(id) self.engine_client.delete_function(id)

View File

@ -102,6 +102,25 @@ class TestFunctionController(base.APITest):
) )
self._assertDictContainsSubset(resp.json, body) self._assertDictContainsSubset(resp.json, body)
def test_post_swift_not_enough_params(self):
body = {
'name': 'swift_function',
'code': json.dumps(
{
"source": "swift",
"swift": {"container": "fake-container"}
}
),
'runtime_id': self.runtime_id,
}
resp = self.app.post(
'/v1/functions',
params=body,
expect_errors=True
)
self.assertEqual(400, resp.status_int)
@mock.patch('qinling.utils.openstack.keystone.get_swiftclient') @mock.patch('qinling.utils.openstack.keystone.get_swiftclient')
@mock.patch('qinling.context.AuthHook.before') @mock.patch('qinling.context.AuthHook.before')
def test_post_swift_size_exceed(self, mock_auth, mock_client): def test_post_swift_size_exceed(self, mock_auth, mock_client):
@ -242,6 +261,78 @@ class TestFunctionController(base.APITest):
self.assertEqual(400, resp.status_int) self.assertEqual(400, resp.status_int)
@mock.patch('qinling.rpc.EngineClient.delete_function')
@mock.patch('qinling.utils.etcd_util.delete_function')
@mock.patch('qinling.utils.openstack.swift.check_object')
@mock.patch('qinling.context.AuthHook.before')
def test_put_swift_function(self, mock_auth, mock_check, mock_etcd_delete,
mock_func_delete):
self.override_config('auth_enable', True, group='pecan')
mock_check.return_value = True
db_func = self.create_function(
runtime_id=self.runtime_id,
code={
"source": "swift",
"swift": {"container": "fake-container", "object": "fake-obj"}
}
)
body = {
'code': json.dumps(
{
"source": "swift",
"swift": {"object": "new-obj"}
}
),
}
resp = self.app.put_json('/v1/functions/%s' % db_func.id, body)
self.assertEqual(200, resp.status_int)
swift_info = {
'code': {
"source": "swift",
"swift": {"container": "fake-container", "object": "new-obj"}
}
}
self._assertDictContainsSubset(resp.json, swift_info)
@mock.patch('qinling.rpc.EngineClient.delete_function')
@mock.patch('qinling.utils.etcd_util.delete_function')
@mock.patch('qinling.utils.openstack.swift.check_object')
@mock.patch('qinling.context.AuthHook.before')
def test_put_swift_function_without_source(self, mock_auth, mock_check,
mock_etcd_delete,
mock_func_delete):
self.override_config('auth_enable', True, group='pecan')
mock_check.return_value = True
db_func = self.create_function(
runtime_id=self.runtime_id,
code={
"source": "swift",
"swift": {"container": "fake-container", "object": "fake-obj"}
}
)
body = {
'code': json.dumps(
{
"swift": {"object": "new-obj"}
}
),
}
resp = self.app.put_json('/v1/functions/%s' % db_func.id, body)
self.assertEqual(200, resp.status_int)
swift_info = {
'code': {
"source": "swift",
"swift": {"container": "fake-container", "object": "new-obj"}
}
}
self._assertDictContainsSubset(resp.json, swift_info)
def test_put_cpu_with_type_error(self): def test_put_cpu_with_type_error(self):
db_func = self.create_function(runtime_id=self.runtime_id) db_func = self.create_function(runtime_id=self.runtime_id)

View File

@ -182,7 +182,7 @@ class DbTestCase(BaseTest):
return runtime return runtime
def create_function(self, runtime_id=None): def create_function(self, runtime_id=None, code=None):
if not runtime_id: if not runtime_id:
runtime_id = self.create_runtime().id runtime_id = self.create_runtime().id
@ -190,7 +190,7 @@ class DbTestCase(BaseTest):
{ {
'name': self.rand_name('function', prefix=self.prefix), 'name': self.rand_name('function', prefix=self.prefix),
'runtime_id': runtime_id, 'runtime_id': runtime_id,
'code': {"source": "package", "md5sum": "fake_md5"}, 'code': code or {"source": "package", "md5sum": "fake_md5"},
'entry': 'main.main', 'entry': 'main.main',
# 'auth_enable' is disabled by default, we create runtime for # 'auth_enable' is disabled by default, we create runtime for
# default tenant. # default tenant.