From fa10083c3bb5d65720c26dae752680ddf11c06fb Mon Sep 17 00:00:00 2001 From: Lingxian Kong Date: Mon, 19 Jun 2017 23:07:27 +1200 Subject: [PATCH] Support to sepcify module.function for python function Currenty, the function entry is hard-coded to be 'main.main' which is not flexible. This patch adds support for specifying module name and function name in the code package. Change-Id: I92ea36f668073f380a4aef4526a6fad321d8cc95 --- qinling/api/controllers/v1/function.py | 2 +- qinling/engine/default_engine.py | 3 +- qinling/orchestrator/kubernetes/manager.py | 9 +++--- runtimes/python2/server.py | 35 ++++++++++++++-------- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/qinling/api/controllers/v1/function.py b/qinling/api/controllers/v1/function.py index 2ab5abf1..e8544a29 100644 --- a/qinling/api/controllers/v1/function.py +++ b/qinling/api/controllers/v1/function.py @@ -103,7 +103,7 @@ class FunctionsController(rest.RestController): 'description': kwargs.get('description'), 'runtime_id': kwargs.get('runtime_id'), 'code': json.loads(kwargs['code']), - 'entry': kwargs.get('entry', 'main'), + 'entry': kwargs.get('entry', 'main.main'), } source = values['code'].get('source') diff --git a/qinling/engine/default_engine.py b/qinling/engine/default_engine.py index 2751ce9d..867a61d0 100644 --- a/qinling/engine/default_engine.py +++ b/qinling/engine/default_engine.py @@ -101,7 +101,8 @@ class DefaultEngine(object): image=image, identifier=identifier, labels=labels, - input=input + input=input, + entry=function.entry ) output = self.orchestrator.run_execution( diff --git a/qinling/orchestrator/kubernetes/manager.py b/qinling/orchestrator/kubernetes/manager.py index 1e58267f..15fabfce 100644 --- a/qinling/orchestrator/kubernetes/manager.py +++ b/qinling/orchestrator/kubernetes/manager.py @@ -157,7 +157,7 @@ class KubernetesManager(base.OrchestratorBase): return pod - def _prepare_pod(self, pod, deployment_name, function_id, labels): + def _prepare_pod(self, pod, deployment_name, function_id, labels, entry): """Pod preparation. 1. Update pod labels. @@ -230,7 +230,8 @@ class KubernetesManager(base.OrchestratorBase): data = { 'download_url': download_url, 'function_id': function_id, - 'token': context.get_ctx().auth_token + 'entry': entry, + 'token': context.get_ctx().auth_token, } LOG.debug( @@ -271,7 +272,7 @@ class KubernetesManager(base.OrchestratorBase): ) def prepare_execution(self, function_id, image=None, identifier=None, - labels=None, input=None): + labels=None, input=None, entry='main.main'): """Prepare service URL for function. For image function, create a single pod with input, so the function @@ -291,7 +292,7 @@ class KubernetesManager(base.OrchestratorBase): if not pod: raise exc.OrchestratorException('No pod available.') - return self._prepare_pod(pod, identifier, function_id, labels) + return self._prepare_pod(pod, identifier, function_id, labels, entry) def run_execution(self, function_id, input=None, identifier=None, service_url=None): diff --git a/runtimes/python2/server.py b/runtimes/python2/server.py index 3a140bee..d725173e 100644 --- a/runtimes/python2/server.py +++ b/runtimes/python2/server.py @@ -26,46 +26,56 @@ from flask import Response import requests app = Flask(__name__) -file_name = '' +zip_file = '' +function_module = 'main' +function_method = 'main' @app.route('/download', methods=['POST']) def download(): download_url = request.form['download_url'] function_id = request.form['function_id'] + entry = request.form['entry'] token = request.form.get('token') headers = {} if token: headers = {'X-Auth-Token': token} - global file_name - file_name = '%s.zip' % function_id + global zip_file + zip_file = '%s.zip' % function_id app.logger.info( - 'Request received, download_url:%s, headers: %s' % - (download_url, headers) + 'Request received, download_url:%s, headers: %s, entry: %s' % + (download_url, headers, entry) ) r = requests.get(download_url, headers=headers, stream=True) - with open(file_name, 'wb') as fd: + with open(zip_file, 'wb') as fd: for chunk in r.iter_content(chunk_size=65535): fd.write(chunk) - if not zipfile.is_zipfile(file_name): + if not zipfile.is_zipfile(zip_file): abort(500) - app.logger.info('Code package downloaded to %s' % file_name) + app.logger.info('Code package downloaded to %s' % zip_file) + + global function_module + global function_method + function_module, function_method = tuple(entry.rsplit('.', 1)) return 'success' @app.route('/execute', methods=['POST']) def execute(): - global file_name - importer = zipimport.zipimporter(file_name) - module = importer.load_module('main') + global zip_file + global function_module + global function_method + + importer = zipimport.zipimporter(zip_file) + module = importer.load_module(function_module) input = {} if request.form: @@ -77,7 +87,8 @@ def execute(): start = time.time() try: - result = module.main(**input) + func = getattr(module, function_method) + result = func(**input) except Exception as e: result = str(e)