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
This commit is contained in:
Lingxian Kong 2017-06-19 23:07:27 +12:00
parent 0d3ba2f7c8
commit fa10083c3b
4 changed files with 31 additions and 18 deletions

View File

@ -103,7 +103,7 @@ class FunctionsController(rest.RestController):
'description': kwargs.get('description'), 'description': kwargs.get('description'),
'runtime_id': kwargs.get('runtime_id'), 'runtime_id': kwargs.get('runtime_id'),
'code': json.loads(kwargs['code']), 'code': json.loads(kwargs['code']),
'entry': kwargs.get('entry', 'main'), 'entry': kwargs.get('entry', 'main.main'),
} }
source = values['code'].get('source') source = values['code'].get('source')

View File

@ -101,7 +101,8 @@ class DefaultEngine(object):
image=image, image=image,
identifier=identifier, identifier=identifier,
labels=labels, labels=labels,
input=input input=input,
entry=function.entry
) )
output = self.orchestrator.run_execution( output = self.orchestrator.run_execution(

View File

@ -157,7 +157,7 @@ class KubernetesManager(base.OrchestratorBase):
return pod 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. """Pod preparation.
1. Update pod labels. 1. Update pod labels.
@ -230,7 +230,8 @@ class KubernetesManager(base.OrchestratorBase):
data = { data = {
'download_url': download_url, 'download_url': download_url,
'function_id': function_id, 'function_id': function_id,
'token': context.get_ctx().auth_token 'entry': entry,
'token': context.get_ctx().auth_token,
} }
LOG.debug( LOG.debug(
@ -271,7 +272,7 @@ class KubernetesManager(base.OrchestratorBase):
) )
def prepare_execution(self, function_id, image=None, identifier=None, 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. """Prepare service URL for function.
For image function, create a single pod with input, so the function For image function, create a single pod with input, so the function
@ -291,7 +292,7 @@ class KubernetesManager(base.OrchestratorBase):
if not pod: if not pod:
raise exc.OrchestratorException('No pod available.') 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, def run_execution(self, function_id, input=None, identifier=None,
service_url=None): service_url=None):

View File

@ -26,46 +26,56 @@ from flask import Response
import requests import requests
app = Flask(__name__) app = Flask(__name__)
file_name = '' zip_file = ''
function_module = 'main'
function_method = 'main'
@app.route('/download', methods=['POST']) @app.route('/download', methods=['POST'])
def download(): def download():
download_url = request.form['download_url'] download_url = request.form['download_url']
function_id = request.form['function_id'] function_id = request.form['function_id']
entry = request.form['entry']
token = request.form.get('token') token = request.form.get('token')
headers = {} headers = {}
if token: if token:
headers = {'X-Auth-Token': token} headers = {'X-Auth-Token': token}
global file_name global zip_file
file_name = '%s.zip' % function_id zip_file = '%s.zip' % function_id
app.logger.info( app.logger.info(
'Request received, download_url:%s, headers: %s' % 'Request received, download_url:%s, headers: %s, entry: %s' %
(download_url, headers) (download_url, headers, entry)
) )
r = requests.get(download_url, headers=headers, stream=True) 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): for chunk in r.iter_content(chunk_size=65535):
fd.write(chunk) fd.write(chunk)
if not zipfile.is_zipfile(file_name): if not zipfile.is_zipfile(zip_file):
abort(500) 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' return 'success'
@app.route('/execute', methods=['POST']) @app.route('/execute', methods=['POST'])
def execute(): def execute():
global file_name global zip_file
importer = zipimport.zipimporter(file_name) global function_module
module = importer.load_module('main') global function_method
importer = zipimport.zipimporter(zip_file)
module = importer.load_module(function_module)
input = {} input = {}
if request.form: if request.form:
@ -77,7 +87,8 @@ def execute():
start = time.time() start = time.time()
try: try:
result = module.main(**input) func = getattr(module, function_method)
result = func(**input)
except Exception as e: except Exception as e:
result = str(e) result = str(e)