diff --git a/qinling/api/controllers/v1/function.py b/qinling/api/controllers/v1/function.py index 2e5cf975..bce95f98 100644 --- a/qinling/api/controllers/v1/function.py +++ b/qinling/api/controllers/v1/function.py @@ -310,21 +310,27 @@ class FunctionsController(rest.RestController): ) pre_source = pre_func.code['source'] - pre_md5sum = pre_func.code['md5sum'] + pre_md5sum = pre_func.code.get('md5sum') + if source and source != pre_source: raise exc.InputException( "The function code type can not be changed." ) - if md5sum and md5sum == pre_md5sum: - raise exc.InputException( - "The function code checksum is not changed." - ) - if source == constants.IMAGE_FUNCTION: + + if pre_source == constants.IMAGE_FUNCTION: raise exc.InputException( "The image type function code can not be changed." ) + + # Package type function. 'code' and 'entry' make sense only if + # 'package' is provided if (pre_source == constants.PACKAGE_FUNCTION and values.get('package') is not None): + if md5sum and md5sum == pre_md5sum: + raise exc.InputException( + "The function code checksum is not changed." + ) + # Update the package data. data = values['package'].file.read() md5sum = self.storage_provider.store( @@ -337,17 +343,23 @@ class FunctionsController(rest.RestController): {"md5sum": md5sum, "source": pre_source} ) values.pop('package') + + # Swift type function if pre_source == constants.SWIFT_FUNCTION: swift_info = values['code'].get('swift', {}) self._check_swift(swift_info.get('container'), swift_info.get('object')) - # Delete allocated resources in orchestrator and etcd keys. + # Delete allocated resources in orchestrator and etcd. self.engine_client.delete_function(id) etcd_util.delete_function(id) func_db = db_api.update_function(id, values) + # Delete function package if needed + if pre_md5sum: + self.storage_provider.delete(ctx.projectid, id, pre_md5sum) + pecan.response.status = 200 return resources.Function.from_dict(func_db.to_dict()).to_dict() diff --git a/qinling/tests/unit/api/controllers/v1/test_function.py b/qinling/tests/unit/api/controllers/v1/test_function.py index b984793e..1ece42d9 100644 --- a/qinling/tests/unit/api/controllers/v1/test_function.py +++ b/qinling/tests/unit/api/controllers/v1/test_function.py @@ -141,8 +141,10 @@ class TestFunctionController(base.APITest): @mock.patch('qinling.utils.etcd_util.delete_function') @mock.patch('qinling.storage.file_system.FileSystemStorage.store') + @mock.patch('qinling.storage.file_system.FileSystemStorage.delete') @mock.patch('qinling.rpc.EngineClient.delete_function') - def test_put_package(self, mock_delete_func, mock_store, mock_etcd_del): + def test_put_package(self, mock_delete_func, mock_delete, mock_store, + mock_etcd_del): db_func = self.create_function( runtime_id=self.runtime_id, prefix=TEST_CASE_NAME ) @@ -158,8 +160,11 @@ class TestFunctionController(base.APITest): self.assertEqual(200, resp.status_int) self.assertEqual(1, mock_store.call_count) self.assertEqual('fake_md5_changed', resp.json['code'].get('md5sum')) + mock_delete_func.assert_called_once_with(db_func.id) mock_etcd_del.assert_called_once_with(db_func.id) + mock_delete.assert_called_once_with(unit_base.DEFAULT_PROJECT_ID, + db_func.id, "fake_md5") def test_put_package_same_md5(self): db_func = self.create_function(