diff --git a/.gitignore b/.gitignore
index fe24b660..62970b44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@ test/*.zip
.p*
*.pyc
*.zip*
+.settings/
*.log
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..eb5704f6
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,16 @@
+FROM python:3-alpine
+
+RUN mkdir -p /usr/src/app
+WORKDIR /usr/src/app
+
+COPY requirements.txt /usr/src/app/
+
+RUN pip3 install --no-cache-dir -r requirements.txt
+
+COPY . /usr/src/app
+
+EXPOSE 8080
+
+ENTRYPOINT ["python3"]
+
+CMD ["-m", "swagger_server"]
\ No newline at end of file
diff --git a/README.md b/README.md
index 444d0fa1..fca7a1e5 100644
--- a/README.md
+++ b/README.md
@@ -16,4 +16,4 @@
- Deploy the cluster! Example with Amazon EC2:
```
./ec3 launch mycluster kubernetes_oscar ubuntu-ec2 -a auth.txt
- ```
\ No newline at end of file
+ ```
diff --git a/examples/imagemagick/README.md b/examples/imagemagick/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..2264f67f
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+connexion == 1.1.15
+python_dateutil == 2.6.0
+setuptools >= 21.0.0
\ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 00000000..81f8352e
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,35 @@
+# coding: utf-8
+
+import sys
+from setuptools import setup, find_packages
+
+NAME = "swagger_server"
+VERSION = "1.0.0"
+
+# To install the library, run the following
+#
+# python setup.py install
+#
+# prerequisite: setuptools
+# http://pypi.python.org/pypi/setuptools
+
+REQUIRES = ["connexion"]
+
+setup(
+ name=NAME,
+ version=VERSION,
+ description="On-premises Serverless Container-aware ARchitectures API Gateway",
+ author_email="",
+ url="",
+ keywords=["Swagger", "On-premises Serverless Container-aware ARchitectures API Gateway"],
+ install_requires=REQUIRES,
+ packages=find_packages(),
+ package_data={'': ['swagger/swagger.yaml']},
+ include_package_data=True,
+ entry_points={
+ 'console_scripts': ['swagger_server=__main__:main']},
+ long_description="""\
+ OSCAR API documentation
+ """
+)
+
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100644
index 00000000..5e3dbbaa
--- /dev/null
+++ b/src/__init__.py
@@ -0,0 +1,18 @@
+# SCAR - Serverless Container-aware ARchitectures
+# Copyright (C) 2011 - GRyCAP - Universitat Politecnica de Valencia
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+__all__ = ['cmdtemplate','request','utils']
\ No newline at end of file
diff --git a/src/cmdtemplate.py b/src/cmdtemplate.py
new file mode 100644
index 00000000..6e8c1dcd
--- /dev/null
+++ b/src/cmdtemplate.py
@@ -0,0 +1,73 @@
+# SCAR - Serverless Container-aware ARchitectures
+# Copyright (C) 2011 - GRyCAP - Universitat Politecnica de Valencia
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import abc
+from enum import Enum
+
+class CallType(Enum):
+ INIT = "init"
+ INVOKE = "invoke"
+ RUN = "run"
+ UPDATE = "update"
+ LS = "ls"
+ RM = "rm"
+ LOG = "log"
+ PUT = "put"
+ GET = "get"
+
+class Commands(metaclass=abc.ABCMeta):
+ ''' All the different cloud provider controllers must inherit
+ from this class to ensure that the commands are defined consistently'''
+
+ @abc.abstractmethod
+ def init(self):
+ pass
+
+ @abc.abstractmethod
+ def invoke(self):
+ pass
+
+ @abc.abstractmethod
+ def run(self):
+ pass
+
+ @abc.abstractmethod
+ def update(self):
+ pass
+
+ @abc.abstractmethod
+ def ls(self):
+ pass
+
+ @abc.abstractmethod
+ def rm(self):
+ pass
+
+ @abc.abstractmethod
+ def log(self):
+ pass
+
+ @abc.abstractmethod
+ def put(self):
+ pass
+
+ @abc.abstractmethod
+ def get(self):
+ pass
+
+ @abc.abstractmethod
+ def parse_arguments(self, args):
+ pass
diff --git a/src/providers/openfaas/__init__.py b/src/providers/openfaas/__init__.py
new file mode 100644
index 00000000..aa10ae36
--- /dev/null
+++ b/src/providers/openfaas/__init__.py
@@ -0,0 +1,18 @@
+# SCAR - Serverless Container-aware ARchitectures
+# Copyright (C) 2011 - GRyCAP - Universitat Politecnica de Valencia
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+__all__ = ['controller']
\ No newline at end of file
diff --git a/src/providers/onpremises/openfaas/function/README.md b/src/providers/openfaas/cloud/openfaas/README.md
similarity index 100%
rename from src/providers/onpremises/openfaas/function/README.md
rename to src/providers/openfaas/cloud/openfaas/README.md
diff --git a/src/providers/onpremises/openfaas/function/supervisor.py b/src/providers/openfaas/cloud/openfaas/supervisor.py
similarity index 99%
rename from src/providers/onpremises/openfaas/function/supervisor.py
rename to src/providers/openfaas/cloud/openfaas/supervisor.py
index 023c58e4..ff62d135 100644
--- a/src/providers/onpremises/openfaas/function/supervisor.py
+++ b/src/providers/openfaas/cloud/openfaas/supervisor.py
@@ -93,5 +93,3 @@ def launch_user_script():
os.makedirs(output_folder, exist_ok=True)
launch_user_script()
upload_output()
-
-
diff --git a/src/providers/openfaas/controller.py b/src/providers/openfaas/controller.py
new file mode 100644
index 00000000..332d45a0
--- /dev/null
+++ b/src/providers/openfaas/controller.py
@@ -0,0 +1,86 @@
+# SCAR - Serverless Container-aware ARchitectures
+# Copyright (C) 2011 - GRyCAP - Universitat Politecnica de Valencia
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+from src.cmdtemplate import Commands
+import src.utils as utils
+import requests
+from flask import Response
+
+def flask_response(func):
+ '''
+ Decorator used to create a flask Response
+ '''
+ def wrapper(*args, **kwargs):
+ r = func(*args, **kwargs)
+ kwargs = {'response' : r.content, 'status' : str(r.status_code), 'headers' : r.headers.items()}
+ return Response(**kwargs)
+ return wrapper
+
+class OpenFaas(Commands):
+
+ functions_path = '/system/functions'
+ function_info = '/system/function/'
+ invoke_req_response_function = '/function/'
+ invoke_async_function = '/async-function/'
+ system_info = '/system/info'
+
+ def __init__(self):
+ self.endpoint = utils.get_environment_variable("OPENFAAS_URL")
+
+ @flask_response
+ def ls(self, function_name=None):
+ path = self.functions_path
+ if function_name:
+ path = self.function_info + function_name
+ return requests.get(self.endpoint + path)
+
+ @flask_response
+ def init(self, **kwargs):
+ print(kwargs)
+ path = self.functions_path
+ r = requests.post(self.endpoint + path, json=kwargs)
+ return r
+
+ @flask_response
+ def invoke(self, function_name, body, asynch=False):
+ path = self.invoke_req_response_function
+ if asynch:
+ path = self.invoke_async_function
+ return requests.post(self.endpoint + path + function_name, data=body)
+
+ def run(self):
+ pass
+
+ def update(self):
+ pass
+
+ @flask_response
+ def rm(self, function_name):
+ payload = { 'functionName' : function_name }
+ return requests.delete(self.endpoint + self.functions_path, json=payload)
+
+ def log(self):
+ pass
+
+ def put(self):
+ pass
+
+ def get(self):
+ pass
+
+ def parse_arguments(self, args):
+ pass
+
diff --git a/src/utils.py b/src/utils.py
new file mode 100644
index 00000000..49a6e13b
--- /dev/null
+++ b/src/utils.py
@@ -0,0 +1,165 @@
+# SCAR - Serverless Container-aware ARchitectures
+# Copyright (C) 2011 - GRyCAP - Universitat Politecnica de Valencia
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import base64
+import json
+import os
+import re
+import subprocess
+import tarfile
+import tempfile
+import uuid
+
+def join_paths(*paths):
+ return os.path.join(*paths)
+
+def get_temp_dir():
+ return tempfile.gettempdir()
+
+def lazy_property(func):
+ ''' A decorator that makes a property lazy-evaluated.'''
+ attr_name = '_lazy_' + func.__name__
+
+ @property
+ def _lazy_property(self):
+ if not hasattr(self, attr_name):
+ setattr(self, attr_name, func(self))
+ return getattr(self, attr_name)
+ return _lazy_property
+
+def find_expression(string_to_search, rgx_pattern):
+ '''Returns the first group that matches the rgx_pattern in the string_to_search'''
+ if string_to_search:
+ pattern = re.compile(rgx_pattern)
+ match = pattern.search(string_to_search)
+ if match :
+ return match.group()
+
+def base64_to_utf8_string(value):
+ return base64.b64decode(value).decode('utf-8')
+
+def utf8_to_base64_string(value):
+ return base64.b64encode(value).decode('utf-8')
+
+def dict_to_base64_string(value):
+ return base64.b64encode(json.dumps(value)).decode("utf-8")
+
+def divide_list_in_chunks(elements, chunk_size):
+ """Yield successive n-sized chunks from th elements list."""
+ if len(elements) == 0:
+ yield []
+ for i in range(0, len(elements), chunk_size):
+ yield elements[i:i + chunk_size]
+
+def get_random_uuid4_str():
+ return str(uuid.uuid4())
+
+def merge_dicts(d1, d2):
+ '''
+ Merge 'd1' and 'd2' dicts into 'd1'.
+ 'd2' has precedence over 'd1'
+ '''
+ for k,v in d2.items():
+ if v:
+ if k not in d1:
+ d1[k] = v
+ elif type(v) is dict:
+ d1[k] = merge_dicts(d1[k], v)
+ elif type(v) is list:
+ d1[k] += v
+ return d1
+
+def is_value_in_dict(dictionary, value):
+ return value in dictionary and dictionary[value]
+
+def get_tree_size(path):
+ """Return total size of files in given path and subdirs."""
+ total = 0
+ for entry in os.scandir(path):
+ if entry.is_dir(follow_symlinks=False):
+ total += get_tree_size(entry.path)
+ else:
+ total += entry.stat(follow_symlinks=False).st_size
+ return total
+
+def get_all_files_in_directory(dir_path):
+ files = []
+ for dirname, _, filenames in os.walk(dir_path):
+ for filename in filenames:
+ files.append(os.path.join(dirname, filename))
+ return files
+
+def get_file_size(file_path):
+ '''Return file size in bytes'''
+ return os.stat(file_path).st_size
+
+def create_folder(folder_name):
+ if not os.path.isdir(folder_name):
+ os.makedirs(folder_name, exist_ok=True)
+
+def create_file_with_content(path, content):
+ with open(path, "w") as f:
+ f.write(content)
+
+def read_file(file_path, mode="r"):
+ with open(file_path, mode) as content_file:
+ return content_file.read()
+
+def delete_file(path):
+ if os.path.isfile(path):
+ os.remove(path)
+
+def create_tar_gz(files_to_archive, destination_tar_path):
+ with tarfile.open(destination_tar_path, "w:gz") as tar:
+ for file_path in files_to_archive:
+ tar.add(file_path, arcname=os.path.basename(file_path))
+ return destination_tar_path
+
+def extract_tar_gz(tar_path, destination_path):
+ with tarfile.open(tar_path, "r:gz") as tar:
+ tar.extractall(path=destination_path)
+
+def kill_process(self, process):
+ # Using SIGKILL instead of SIGTERM to ensure the process finalization
+ os.killpg(os.getpgid(process.pid), subprocess.signal.SIGKILL)
+
+def execute_command(command):
+ subprocess.call(command)
+
+def execute_command_and_return_output(command):
+ return subprocess.check_output(command).decode("utf-8")
+
+def is_variable_in_environment(variable):
+ return is_value_in_dict(os.environ, variable)
+
+def set_environment_variable(key, variable):
+ if key and variable:
+ os.environ[key] = variable
+
+def get_environment_variable(variable):
+ if is_variable_in_environment(variable):
+ return os.environ[variable]
+
+def parse_arg_list(arg_keys, cmd_args):
+ result = {}
+ for key in arg_keys:
+ if type(key) is tuple:
+ if key[0] in cmd_args and cmd_args[key[0]]:
+ result[key[1]] = cmd_args[key[0]]
+ else:
+ if key in cmd_args and cmd_args[key]:
+ result[key] = cmd_args[key]
+ return result
diff --git a/swagger_server/__init__.py b/swagger_server/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/swagger_server/__main__.py b/swagger_server/__main__.py
new file mode 100644
index 00000000..b87cab87
--- /dev/null
+++ b/swagger_server/__main__.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+
+import connexion
+
+from swagger_server import encoder
+
+
+def main():
+ app = connexion.App(__name__, specification_dir='./swagger/')
+ app.app.json_encoder = encoder.JSONEncoder
+ app.add_api('swagger.yaml', arguments={'title': 'On-premises Serverless Container-aware ARchitectures API Gateway'})
+ app.run(port=8080)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/swagger_server/controllers/__init__.py b/swagger_server/controllers/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/swagger_server/controllers/default_controller.py b/swagger_server/controllers/default_controller.py
new file mode 100644
index 00000000..d929be8a
--- /dev/null
+++ b/swagger_server/controllers/default_controller.py
@@ -0,0 +1,89 @@
+import connexion
+
+from swagger_server.models.delete_function_request import DeleteFunctionRequest
+from swagger_server.models.function_definition import FunctionDefinition
+from src.providers.openfaas.controller import OpenFaas
+
+
+def function_async_function_name_post(functionName, input=None):
+ """Invoke a function asynchronously
+
+ :param functionName: Function name
+ :type functionName: str
+ :param input: (Optional) data to pass to function
+ :type input: str
+
+ :rtype: None
+ """
+ return OpenFaas().invoke(functionName, input, asynch=True)
+
+
+def function_function_name_get(functionName):
+ """Get a summary of an OpenFaaS function
+
+ :param functionName: Function name
+ :type functionName: str
+
+ :rtype: FunctionListEntry
+ """
+ return OpenFaas().ls(functionName)
+
+
+def function_function_name_post(functionName, input=None):
+ """Invoke a function defined in OpenFaaS
+
+ :param functionName: Function name
+ :type functionName: str
+ :param body: (Optional) data to pass to function
+ :type body: str
+
+ :rtype: None
+ """
+ return OpenFaas().invoke(functionName, input)
+
+
+def functions_delete(body):
+ """Remove a deployed function.
+
+ :param body: Function to delete
+ :type body: dict | bytes
+
+ :rtype: None
+ """
+ if connexion.request.is_json:
+ body = DeleteFunctionRequest.from_dict(connexion.request.get_json())
+ return OpenFaas().rm(body.function_name)
+
+
+def functions_get():
+ """Get a list of deployed functions with: stats and image digest
+
+ :rtype: List[FunctionListEntry]
+ """
+ return OpenFaas().ls()
+
+
+def functions_post(body):
+ """Deploy a new function.
+
+ :param body: Function to deploy
+ :type body: dict | bytes
+
+ :rtype: None
+ """
+ if connexion.request.is_json:
+ params = connexion.request.get_json()
+ return OpenFaas().init(**params)
+
+
+def functions_put(body):
+ """Update a function.
+
+ :param body: Function to update
+ :type body: dict | bytes
+
+ :rtype: None
+ """
+ if connexion.request.is_json:
+ body = FunctionDefinition.from_dict(connexion.request.get_json())
+ return 'do some magic!'
diff --git a/swagger_server/encoder.py b/swagger_server/encoder.py
new file mode 100644
index 00000000..61ba4721
--- /dev/null
+++ b/swagger_server/encoder.py
@@ -0,0 +1,20 @@
+from connexion.apps.flask_app import FlaskJSONEncoder
+import six
+
+from swagger_server.models.base_model_ import Model
+
+
+class JSONEncoder(FlaskJSONEncoder):
+ include_nulls = False
+
+ def default(self, o):
+ if isinstance(o, Model):
+ dikt = {}
+ for attr, _ in six.iteritems(o.swagger_types):
+ value = getattr(o, attr)
+ if value is None and not self.include_nulls:
+ continue
+ attr = o.attribute_map[attr]
+ dikt[attr] = value
+ return dikt
+ return FlaskJSONEncoder.default(self, o)
diff --git a/swagger_server/models/__init__.py b/swagger_server/models/__init__.py
new file mode 100644
index 00000000..55ca9d30
--- /dev/null
+++ b/swagger_server/models/__init__.py
@@ -0,0 +1,9 @@
+# coding: utf-8
+
+# flake8: noqa
+from __future__ import absolute_import
+# import models into model package
+from swagger_server.models.delete_function_request import DeleteFunctionRequest
+from swagger_server.models.function_definition import FunctionDefinition
+from swagger_server.models.function_definition_limits import FunctionDefinitionLimits
+from swagger_server.models.function_list_entry import FunctionListEntry
diff --git a/swagger_server/models/base_model_.py b/swagger_server/models/base_model_.py
new file mode 100644
index 00000000..97999c3d
--- /dev/null
+++ b/swagger_server/models/base_model_.py
@@ -0,0 +1,69 @@
+import pprint
+
+import six
+import typing
+
+from swagger_server import util
+
+T = typing.TypeVar('T')
+
+
+class Model(object):
+ # swaggerTypes: The key is attribute name and the
+ # value is attribute type.
+ swagger_types = {}
+
+ # attributeMap: The key is attribute name and the
+ # value is json key in definition.
+ attribute_map = {}
+
+ @classmethod
+ def from_dict(cls: typing.Type[T], dikt) -> T:
+ """Returns the dict as a model"""
+ return util.deserialize_model(dikt, cls)
+
+ def to_dict(self):
+ """Returns the model properties as a dict
+
+ :rtype: dict
+ """
+ result = {}
+
+ for attr, _ in six.iteritems(self.swagger_types):
+ value = getattr(self, attr)
+ if isinstance(value, list):
+ result[attr] = list(map(
+ lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
+ value
+ ))
+ elif hasattr(value, "to_dict"):
+ result[attr] = value.to_dict()
+ elif isinstance(value, dict):
+ result[attr] = dict(map(
+ lambda item: (item[0], item[1].to_dict())
+ if hasattr(item[1], "to_dict") else item,
+ value.items()
+ ))
+ else:
+ result[attr] = value
+
+ return result
+
+ def to_str(self):
+ """Returns the string representation of the model
+
+ :rtype: str
+ """
+ return pprint.pformat(self.to_dict())
+
+ def __repr__(self):
+ """For `print` and `pprint`"""
+ return self.to_str()
+
+ def __eq__(self, other):
+ """Returns true if both objects are equal"""
+ return self.__dict__ == other.__dict__
+
+ def __ne__(self, other):
+ """Returns true if both objects are not equal"""
+ return not self == other
diff --git a/swagger_server/models/delete_function_request.py b/swagger_server/models/delete_function_request.py
new file mode 100644
index 00000000..e30fab51
--- /dev/null
+++ b/swagger_server/models/delete_function_request.py
@@ -0,0 +1,68 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from datetime import date, datetime # noqa: F401
+
+from typing import List, Dict # noqa: F401
+
+from swagger_server.models.base_model_ import Model
+from swagger_server import util
+
+
+class DeleteFunctionRequest(Model):
+ """NOTE: This class is auto generated by the swagger code generator program.
+
+ Do not edit the class manually.
+ """
+
+ def __init__(self, function_name: str=None): # noqa: E501
+ """DeleteFunctionRequest - a model defined in Swagger
+
+ :param function_name: The function_name of this DeleteFunctionRequest. # noqa: E501
+ :type function_name: str
+ """
+ self.swagger_types = {
+ 'function_name': str
+ }
+
+ self.attribute_map = {
+ 'function_name': 'functionName'
+ }
+
+ self._function_name = function_name
+
+ @classmethod
+ def from_dict(cls, dikt) -> 'DeleteFunctionRequest':
+ """Returns the dict as a model
+
+ :param dikt: A dict.
+ :type: dict
+ :return: The DeleteFunctionRequest of this DeleteFunctionRequest. # noqa: E501
+ :rtype: DeleteFunctionRequest
+ """
+ return util.deserialize_model(dikt, cls)
+
+ @property
+ def function_name(self) -> str:
+ """Gets the function_name of this DeleteFunctionRequest.
+
+ Name of deployed function # noqa: E501
+
+ :return: The function_name of this DeleteFunctionRequest.
+ :rtype: str
+ """
+ return self._function_name
+
+ @function_name.setter
+ def function_name(self, function_name: str):
+ """Sets the function_name of this DeleteFunctionRequest.
+
+ Name of deployed function # noqa: E501
+
+ :param function_name: The function_name of this DeleteFunctionRequest.
+ :type function_name: str
+ """
+ if function_name is None:
+ raise ValueError("Invalid value for `function_name`, must not be `None`") # noqa: E501
+
+ self._function_name = function_name
diff --git a/swagger_server/models/function_definition.py b/swagger_server/models/function_definition.py
new file mode 100644
index 00000000..c1bb545c
--- /dev/null
+++ b/swagger_server/models/function_definition.py
@@ -0,0 +1,373 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from datetime import date, datetime # noqa: F401
+
+from typing import List, Dict # noqa: F401
+
+from swagger_server.models.base_model_ import Model
+from swagger_server.models.function_definition_limits import FunctionDefinitionLimits # noqa: F401,E501
+from swagger_server import util
+
+
+class FunctionDefinition(Model):
+ """NOTE: This class is auto generated by the swagger code generator program.
+
+ Do not edit the class manually.
+ """
+
+ def __init__(self, service: str=None, network: str=None, image: str=None, env_process: str=None, env_vars: Dict[str, str]=None, constraints: List[str]=None, labels: List[str]=None, annotations: List[str]=None, secrets: List[str]=None, registry_auth: str=None, limits: FunctionDefinitionLimits=None, requests: FunctionDefinitionLimits=None): # noqa: E501
+ """FunctionDefinition - a model defined in Swagger
+
+ :param service: The service of this FunctionDefinition. # noqa: E501
+ :type service: str
+ :param network: The network of this FunctionDefinition. # noqa: E501
+ :type network: str
+ :param image: The image of this FunctionDefinition. # noqa: E501
+ :type image: str
+ :param env_process: The env_process of this FunctionDefinition. # noqa: E501
+ :type env_process: str
+ :param env_vars: The env_vars of this FunctionDefinition. # noqa: E501
+ :type env_vars: Dict[str, str]
+ :param constraints: The constraints of this FunctionDefinition. # noqa: E501
+ :type constraints: List[str]
+ :param labels: The labels of this FunctionDefinition. # noqa: E501
+ :type labels: List[str]
+ :param annotations: The annotations of this FunctionDefinition. # noqa: E501
+ :type annotations: List[str]
+ :param secrets: The secrets of this FunctionDefinition. # noqa: E501
+ :type secrets: List[str]
+ :param registry_auth: The registry_auth of this FunctionDefinition. # noqa: E501
+ :type registry_auth: str
+ :param limits: The limits of this FunctionDefinition. # noqa: E501
+ :type limits: FunctionDefinitionLimits
+ :param requests: The requests of this FunctionDefinition. # noqa: E501
+ :type requests: FunctionDefinitionLimits
+ """
+ self.swagger_types = {
+ 'service': str,
+ 'network': str,
+ 'image': str,
+ 'env_process': str,
+ 'env_vars': Dict[str, str],
+ 'constraints': List[str],
+ 'labels': List[str],
+ 'annotations': List[str],
+ 'secrets': List[str],
+ 'registry_auth': str,
+ 'limits': FunctionDefinitionLimits,
+ 'requests': FunctionDefinitionLimits
+ }
+
+ self.attribute_map = {
+ 'service': 'service',
+ 'network': 'network',
+ 'image': 'image',
+ 'env_process': 'envProcess',
+ 'env_vars': 'envVars',
+ 'constraints': 'constraints',
+ 'labels': 'labels',
+ 'annotations': 'annotations',
+ 'secrets': 'secrets',
+ 'registry_auth': 'registryAuth',
+ 'limits': 'limits',
+ 'requests': 'requests'
+ }
+
+ self._service = service
+ self._network = network
+ self._image = image
+ self._env_process = env_process
+ self._env_vars = env_vars
+ self._constraints = constraints
+ self._labels = labels
+ self._annotations = annotations
+ self._secrets = secrets
+ self._registry_auth = registry_auth
+ self._limits = limits
+ self._requests = requests
+
+ @classmethod
+ def from_dict(cls, dikt) -> 'FunctionDefinition':
+ """Returns the dict as a model
+
+ :param dikt: A dict.
+ :type: dict
+ :return: The FunctionDefinition of this FunctionDefinition. # noqa: E501
+ :rtype: FunctionDefinition
+ """
+ return util.deserialize_model(dikt, cls)
+
+ @property
+ def service(self) -> str:
+ """Gets the service of this FunctionDefinition.
+
+ Name of deployed function # noqa: E501
+
+ :return: The service of this FunctionDefinition.
+ :rtype: str
+ """
+ return self._service
+
+ @service.setter
+ def service(self, service: str):
+ """Sets the service of this FunctionDefinition.
+
+ Name of deployed function # noqa: E501
+
+ :param service: The service of this FunctionDefinition.
+ :type service: str
+ """
+ if service is None:
+ raise ValueError("Invalid value for `service`, must not be `None`") # noqa: E501
+
+ self._service = service
+
+ @property
+ def network(self) -> str:
+ """Gets the network of this FunctionDefinition.
+
+ Docker swarm network, usually func_functions # noqa: E501
+
+ :return: The network of this FunctionDefinition.
+ :rtype: str
+ """
+ return self._network
+
+ @network.setter
+ def network(self, network: str):
+ """Sets the network of this FunctionDefinition.
+
+ Docker swarm network, usually func_functions # noqa: E501
+
+ :param network: The network of this FunctionDefinition.
+ :type network: str
+ """
+
+ self._network = network
+
+ @property
+ def image(self) -> str:
+ """Gets the image of this FunctionDefinition.
+
+ Docker image in accessible registry # noqa: E501
+
+ :return: The image of this FunctionDefinition.
+ :rtype: str
+ """
+ return self._image
+
+ @image.setter
+ def image(self, image: str):
+ """Sets the image of this FunctionDefinition.
+
+ Docker image in accessible registry # noqa: E501
+
+ :param image: The image of this FunctionDefinition.
+ :type image: str
+ """
+ if image is None:
+ raise ValueError("Invalid value for `image`, must not be `None`") # noqa: E501
+
+ self._image = image
+
+ @property
+ def env_process(self) -> str:
+ """Gets the env_process of this FunctionDefinition.
+
+ Process for watchdog to fork # noqa: E501
+
+ :return: The env_process of this FunctionDefinition.
+ :rtype: str
+ """
+ return self._env_process
+
+ @env_process.setter
+ def env_process(self, env_process: str):
+ """Sets the env_process of this FunctionDefinition.
+
+ Process for watchdog to fork # noqa: E501
+
+ :param env_process: The env_process of this FunctionDefinition.
+ :type env_process: str
+ """
+ if env_process is None:
+ raise ValueError("Invalid value for `env_process`, must not be `None`") # noqa: E501
+
+ self._env_process = env_process
+
+ @property
+ def env_vars(self) -> Dict[str, str]:
+ """Gets the env_vars of this FunctionDefinition.
+
+ Overrides to environmental variables # noqa: E501
+
+ :return: The env_vars of this FunctionDefinition.
+ :rtype: Dict[str, str]
+ """
+ return self._env_vars
+
+ @env_vars.setter
+ def env_vars(self, env_vars: Dict[str, str]):
+ """Sets the env_vars of this FunctionDefinition.
+
+ Overrides to environmental variables # noqa: E501
+
+ :param env_vars: The env_vars of this FunctionDefinition.
+ :type env_vars: Dict[str, str]
+ """
+
+ self._env_vars = env_vars
+
+ @property
+ def constraints(self) -> List[str]:
+ """Gets the constraints of this FunctionDefinition.
+
+
+ :return: The constraints of this FunctionDefinition.
+ :rtype: List[str]
+ """
+ return self._constraints
+
+ @constraints.setter
+ def constraints(self, constraints: List[str]):
+ """Sets the constraints of this FunctionDefinition.
+
+
+ :param constraints: The constraints of this FunctionDefinition.
+ :type constraints: List[str]
+ """
+
+ self._constraints = constraints
+
+ @property
+ def labels(self) -> List[str]:
+ """Gets the labels of this FunctionDefinition.
+
+ An array of labels used by the back-end for making scheduling or routing decisions # noqa: E501
+
+ :return: The labels of this FunctionDefinition.
+ :rtype: List[str]
+ """
+ return self._labels
+
+ @labels.setter
+ def labels(self, labels: List[str]):
+ """Sets the labels of this FunctionDefinition.
+
+ An array of labels used by the back-end for making scheduling or routing decisions # noqa: E501
+
+ :param labels: The labels of this FunctionDefinition.
+ :type labels: List[str]
+ """
+
+ self._labels = labels
+
+ @property
+ def annotations(self) -> List[str]:
+ """Gets the annotations of this FunctionDefinition.
+
+ An array of annotations used by the back-end for management, orchestration, events and build tasks # noqa: E501
+
+ :return: The annotations of this FunctionDefinition.
+ :rtype: List[str]
+ """
+ return self._annotations
+
+ @annotations.setter
+ def annotations(self, annotations: List[str]):
+ """Sets the annotations of this FunctionDefinition.
+
+ An array of annotations used by the back-end for management, orchestration, events and build tasks # noqa: E501
+
+ :param annotations: The annotations of this FunctionDefinition.
+ :type annotations: List[str]
+ """
+
+ self._annotations = annotations
+
+ @property
+ def secrets(self) -> List[str]:
+ """Gets the secrets of this FunctionDefinition.
+
+
+ :return: The secrets of this FunctionDefinition.
+ :rtype: List[str]
+ """
+ return self._secrets
+
+ @secrets.setter
+ def secrets(self, secrets: List[str]):
+ """Sets the secrets of this FunctionDefinition.
+
+
+ :param secrets: The secrets of this FunctionDefinition.
+ :type secrets: List[str]
+ """
+
+ self._secrets = secrets
+
+ @property
+ def registry_auth(self) -> str:
+ """Gets the registry_auth of this FunctionDefinition.
+
+ Private registry base64-encoded basic auth (as present in ~/.docker/config.json) # noqa: E501
+
+ :return: The registry_auth of this FunctionDefinition.
+ :rtype: str
+ """
+ return self._registry_auth
+
+ @registry_auth.setter
+ def registry_auth(self, registry_auth: str):
+ """Sets the registry_auth of this FunctionDefinition.
+
+ Private registry base64-encoded basic auth (as present in ~/.docker/config.json) # noqa: E501
+
+ :param registry_auth: The registry_auth of this FunctionDefinition.
+ :type registry_auth: str
+ """
+
+ self._registry_auth = registry_auth
+
+ @property
+ def limits(self) -> FunctionDefinitionLimits:
+ """Gets the limits of this FunctionDefinition.
+
+
+ :return: The limits of this FunctionDefinition.
+ :rtype: FunctionDefinitionLimits
+ """
+ return self._limits
+
+ @limits.setter
+ def limits(self, limits: FunctionDefinitionLimits):
+ """Sets the limits of this FunctionDefinition.
+
+
+ :param limits: The limits of this FunctionDefinition.
+ :type limits: FunctionDefinitionLimits
+ """
+
+ self._limits = limits
+
+ @property
+ def requests(self) -> FunctionDefinitionLimits:
+ """Gets the requests of this FunctionDefinition.
+
+
+ :return: The requests of this FunctionDefinition.
+ :rtype: FunctionDefinitionLimits
+ """
+ return self._requests
+
+ @requests.setter
+ def requests(self, requests: FunctionDefinitionLimits):
+ """Sets the requests of this FunctionDefinition.
+
+
+ :param requests: The requests of this FunctionDefinition.
+ :type requests: FunctionDefinitionLimits
+ """
+
+ self._requests = requests
diff --git a/swagger_server/models/function_definition_limits.py b/swagger_server/models/function_definition_limits.py
new file mode 100644
index 00000000..f60c5e25
--- /dev/null
+++ b/swagger_server/models/function_definition_limits.py
@@ -0,0 +1,90 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from datetime import date, datetime # noqa: F401
+
+from typing import List, Dict # noqa: F401
+
+from swagger_server.models.base_model_ import Model
+from swagger_server import util
+
+
+class FunctionDefinitionLimits(Model):
+ """NOTE: This class is auto generated by the swagger code generator program.
+
+ Do not edit the class manually.
+ """
+
+ def __init__(self, memory: str=None, cpu: str=None): # noqa: E501
+ """FunctionDefinitionLimits - a model defined in Swagger
+
+ :param memory: The memory of this FunctionDefinitionLimits. # noqa: E501
+ :type memory: str
+ :param cpu: The cpu of this FunctionDefinitionLimits. # noqa: E501
+ :type cpu: str
+ """
+ self.swagger_types = {
+ 'memory': str,
+ 'cpu': str
+ }
+
+ self.attribute_map = {
+ 'memory': 'memory',
+ 'cpu': 'cpu'
+ }
+
+ self._memory = memory
+ self._cpu = cpu
+
+ @classmethod
+ def from_dict(cls, dikt) -> 'FunctionDefinitionLimits':
+ """Returns the dict as a model
+
+ :param dikt: A dict.
+ :type: dict
+ :return: The FunctionDefinition_limits of this FunctionDefinitionLimits. # noqa: E501
+ :rtype: FunctionDefinitionLimits
+ """
+ return util.deserialize_model(dikt, cls)
+
+ @property
+ def memory(self) -> str:
+ """Gets the memory of this FunctionDefinitionLimits.
+
+
+ :return: The memory of this FunctionDefinitionLimits.
+ :rtype: str
+ """
+ return self._memory
+
+ @memory.setter
+ def memory(self, memory: str):
+ """Sets the memory of this FunctionDefinitionLimits.
+
+
+ :param memory: The memory of this FunctionDefinitionLimits.
+ :type memory: str
+ """
+
+ self._memory = memory
+
+ @property
+ def cpu(self) -> str:
+ """Gets the cpu of this FunctionDefinitionLimits.
+
+
+ :return: The cpu of this FunctionDefinitionLimits.
+ :rtype: str
+ """
+ return self._cpu
+
+ @cpu.setter
+ def cpu(self, cpu: str):
+ """Sets the cpu of this FunctionDefinitionLimits.
+
+
+ :param cpu: The cpu of this FunctionDefinitionLimits.
+ :type cpu: str
+ """
+
+ self._cpu = cpu
diff --git a/swagger_server/models/function_list_entry.py b/swagger_server/models/function_list_entry.py
new file mode 100644
index 00000000..75f5fb36
--- /dev/null
+++ b/swagger_server/models/function_list_entry.py
@@ -0,0 +1,272 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from datetime import date, datetime # noqa: F401
+
+from typing import List, Dict # noqa: F401
+
+from swagger_server.models.base_model_ import Model
+from swagger_server import util
+
+
+class FunctionListEntry(Model):
+ """NOTE: This class is auto generated by the swagger code generator program.
+
+ Do not edit the class manually.
+ """
+
+ def __init__(self, name: str=None, image: str=None, invocation_count: float=None, replicas: float=None, available_replicas: float=None, env_process: str=None, labels: Dict[str, str]=None, annotations: Dict[str, str]=None): # noqa: E501
+ """FunctionListEntry - a model defined in Swagger
+
+ :param name: The name of this FunctionListEntry. # noqa: E501
+ :type name: str
+ :param image: The image of this FunctionListEntry. # noqa: E501
+ :type image: str
+ :param invocation_count: The invocation_count of this FunctionListEntry. # noqa: E501
+ :type invocation_count: float
+ :param replicas: The replicas of this FunctionListEntry. # noqa: E501
+ :type replicas: float
+ :param available_replicas: The available_replicas of this FunctionListEntry. # noqa: E501
+ :type available_replicas: float
+ :param env_process: The env_process of this FunctionListEntry. # noqa: E501
+ :type env_process: str
+ :param labels: The labels of this FunctionListEntry. # noqa: E501
+ :type labels: Dict[str, str]
+ :param annotations: The annotations of this FunctionListEntry. # noqa: E501
+ :type annotations: Dict[str, str]
+ """
+ self.swagger_types = {
+ 'name': str,
+ 'image': str,
+ 'invocation_count': float,
+ 'replicas': float,
+ 'available_replicas': float,
+ 'env_process': str,
+ 'labels': Dict[str, str],
+ 'annotations': Dict[str, str]
+ }
+
+ self.attribute_map = {
+ 'name': 'name',
+ 'image': 'image',
+ 'invocation_count': 'invocationCount',
+ 'replicas': 'replicas',
+ 'available_replicas': 'availableReplicas',
+ 'env_process': 'envProcess',
+ 'labels': 'labels',
+ 'annotations': 'annotations'
+ }
+
+ self._name = name
+ self._image = image
+ self._invocation_count = invocation_count
+ self._replicas = replicas
+ self._available_replicas = available_replicas
+ self._env_process = env_process
+ self._labels = labels
+ self._annotations = annotations
+
+ @classmethod
+ def from_dict(cls, dikt) -> 'FunctionListEntry':
+ """Returns the dict as a model
+
+ :param dikt: A dict.
+ :type: dict
+ :return: The FunctionListEntry of this FunctionListEntry. # noqa: E501
+ :rtype: FunctionListEntry
+ """
+ return util.deserialize_model(dikt, cls)
+
+ @property
+ def name(self) -> str:
+ """Gets the name of this FunctionListEntry.
+
+ The name of the function # noqa: E501
+
+ :return: The name of this FunctionListEntry.
+ :rtype: str
+ """
+ return self._name
+
+ @name.setter
+ def name(self, name: str):
+ """Sets the name of this FunctionListEntry.
+
+ The name of the function # noqa: E501
+
+ :param name: The name of this FunctionListEntry.
+ :type name: str
+ """
+ if name is None:
+ raise ValueError("Invalid value for `name`, must not be `None`") # noqa: E501
+
+ self._name = name
+
+ @property
+ def image(self) -> str:
+ """Gets the image of this FunctionListEntry.
+
+ The fully qualified docker image name of the function # noqa: E501
+
+ :return: The image of this FunctionListEntry.
+ :rtype: str
+ """
+ return self._image
+
+ @image.setter
+ def image(self, image: str):
+ """Sets the image of this FunctionListEntry.
+
+ The fully qualified docker image name of the function # noqa: E501
+
+ :param image: The image of this FunctionListEntry.
+ :type image: str
+ """
+ if image is None:
+ raise ValueError("Invalid value for `image`, must not be `None`") # noqa: E501
+
+ self._image = image
+
+ @property
+ def invocation_count(self) -> float:
+ """Gets the invocation_count of this FunctionListEntry.
+
+ The amount of invocations for the specified function # noqa: E501
+
+ :return: The invocation_count of this FunctionListEntry.
+ :rtype: float
+ """
+ return self._invocation_count
+
+ @invocation_count.setter
+ def invocation_count(self, invocation_count: float):
+ """Sets the invocation_count of this FunctionListEntry.
+
+ The amount of invocations for the specified function # noqa: E501
+
+ :param invocation_count: The invocation_count of this FunctionListEntry.
+ :type invocation_count: float
+ """
+ if invocation_count is None:
+ raise ValueError("Invalid value for `invocation_count`, must not be `None`") # noqa: E501
+
+ self._invocation_count = invocation_count
+
+ @property
+ def replicas(self) -> float:
+ """Gets the replicas of this FunctionListEntry.
+
+ The current minimal ammount of replicas # noqa: E501
+
+ :return: The replicas of this FunctionListEntry.
+ :rtype: float
+ """
+ return self._replicas
+
+ @replicas.setter
+ def replicas(self, replicas: float):
+ """Sets the replicas of this FunctionListEntry.
+
+ The current minimal ammount of replicas # noqa: E501
+
+ :param replicas: The replicas of this FunctionListEntry.
+ :type replicas: float
+ """
+ if replicas is None:
+ raise ValueError("Invalid value for `replicas`, must not be `None`") # noqa: E501
+
+ self._replicas = replicas
+
+ @property
+ def available_replicas(self) -> float:
+ """Gets the available_replicas of this FunctionListEntry.
+
+ The current available amount of replicas # noqa: E501
+
+ :return: The available_replicas of this FunctionListEntry.
+ :rtype: float
+ """
+ return self._available_replicas
+
+ @available_replicas.setter
+ def available_replicas(self, available_replicas: float):
+ """Sets the available_replicas of this FunctionListEntry.
+
+ The current available amount of replicas # noqa: E501
+
+ :param available_replicas: The available_replicas of this FunctionListEntry.
+ :type available_replicas: float
+ """
+ if available_replicas is None:
+ raise ValueError("Invalid value for `available_replicas`, must not be `None`") # noqa: E501
+
+ self._available_replicas = available_replicas
+
+ @property
+ def env_process(self) -> str:
+ """Gets the env_process of this FunctionListEntry.
+
+ Process for watchdog to fork # noqa: E501
+
+ :return: The env_process of this FunctionListEntry.
+ :rtype: str
+ """
+ return self._env_process
+
+ @env_process.setter
+ def env_process(self, env_process: str):
+ """Sets the env_process of this FunctionListEntry.
+
+ Process for watchdog to fork # noqa: E501
+
+ :param env_process: The env_process of this FunctionListEntry.
+ :type env_process: str
+ """
+ if env_process is None:
+ raise ValueError("Invalid value for `env_process`, must not be `None`") # noqa: E501
+
+ self._env_process = env_process
+
+ @property
+ def labels(self) -> Dict[str, str]:
+ """Gets the labels of this FunctionListEntry.
+
+
+ :return: The labels of this FunctionListEntry.
+ :rtype: Dict[str, str]
+ """
+ return self._labels
+
+ @labels.setter
+ def labels(self, labels: Dict[str, str]):
+ """Sets the labels of this FunctionListEntry.
+
+
+ :param labels: The labels of this FunctionListEntry.
+ :type labels: Dict[str, str]
+ """
+ if labels is None:
+ raise ValueError("Invalid value for `labels`, must not be `None`") # noqa: E501
+
+ self._labels = labels
+
+ @property
+ def annotations(self) -> Dict[str, str]:
+ """Gets the annotations of this FunctionListEntry.
+
+
+ :return: The annotations of this FunctionListEntry.
+ :rtype: Dict[str, str]
+ """
+ return self._annotations
+
+ @annotations.setter
+ def annotations(self, annotations: Dict[str, str]):
+ """Sets the annotations of this FunctionListEntry.
+
+
+ :param annotations: The annotations of this FunctionListEntry.
+ :type annotations: Dict[str, str]
+ """
+
+ self._annotations = annotations
diff --git a/swagger_server/swagger/swagger.yaml b/swagger_server/swagger/swagger.yaml
new file mode 100644
index 00000000..af0404c2
--- /dev/null
+++ b/swagger_server/swagger/swagger.yaml
@@ -0,0 +1,348 @@
+---
+swagger: "2.0"
+info:
+ description: "OSCAR API documentation"
+ version: "0.0.1"
+ title: "On-premises Serverless Container-aware ARchitectures API Gateway"
+ license:
+ name: "Apache2"
+basePath: "/"
+schemes:
+- "http"
+paths:
+ /functions:
+ get:
+ summary: "Get a list of deployed functions with: stats and image digest"
+ operationId: "functions_get"
+ consumes:
+ - "application/json"
+ produces:
+ - "application/json"
+ parameters: []
+ responses:
+ 200:
+ description: "List of deployed functions."
+ schema:
+ type: "array"
+ items:
+ $ref: "#/definitions/FunctionListEntry"
+ x-swagger-router-controller: "swagger_server.controllers.default_controller"
+ post:
+ summary: "Deploy a new function."
+ description: ""
+ operationId: "functions_post"
+ consumes:
+ - "application/json"
+ produces:
+ - "application/json"
+ parameters:
+ - in: "body"
+ name: "body"
+ description: "Function to deploy"
+ required: true
+ schema:
+ $ref: "#/definitions/FunctionDefinition"
+ responses:
+ 202:
+ description: "Accepted"
+ 400:
+ description: "Bad Request"
+ 500:
+ description: "Internal Server Error"
+ x-swagger-router-controller: "swagger_server.controllers.default_controller"
+ put:
+ summary: "Update a function."
+ description: ""
+ operationId: "functions_put"
+ consumes:
+ - "application/json"
+ produces:
+ - "application/json"
+ parameters:
+ - in: "body"
+ name: "body"
+ description: "Function to update"
+ required: true
+ schema:
+ $ref: "#/definitions/FunctionDefinition"
+ responses:
+ 200:
+ description: "Accepted"
+ 400:
+ description: "Bad Request"
+ 404:
+ description: "Not Found"
+ 500:
+ description: "Internal Server Error"
+ x-swagger-router-controller: "swagger_server.controllers.default_controller"
+ delete:
+ summary: "Remove a deployed function."
+ description: ""
+ operationId: "functions_delete"
+ consumes:
+ - "application/json"
+ produces:
+ - "application/json"
+ parameters:
+ - in: "body"
+ name: "body"
+ description: "Function to delete"
+ required: true
+ schema:
+ $ref: "#/definitions/DeleteFunctionRequest"
+ responses:
+ 200:
+ description: "OK"
+ 400:
+ description: "Bad Request"
+ 404:
+ description: "Not Found"
+ 500:
+ description: "Internal Server Error"
+ x-swagger-router-controller: "swagger_server.controllers.default_controller"
+ /function/async/{functionName}:
+ post:
+ summary: "Invoke a function asynchronously"
+ operationId: "function_async_function_name_post"
+ parameters:
+ - name: "functionName"
+ in: "path"
+ description: "Function name"
+ required: true
+ type: "string"
+ - in: "body"
+ name: "input"
+ description: "(Optional) data to pass to function"
+ required: false
+ schema:
+ type: "string"
+ format: "binary"
+ example: "{\"hello\": \"world\"}"
+ responses:
+ 202:
+ description: "Request accepted and queued"
+ 404:
+ description: "Not Found"
+ 500:
+ description: "Internal Server Error"
+ x-swagger-router-controller: "swagger_server.controllers.default_controller"
+ /function/{functionName}:
+ get:
+ summary: "Get a summary of an OpenFaaS function"
+ operationId: "function_function_name_get"
+ parameters:
+ - name: "functionName"
+ in: "path"
+ description: "Function name"
+ required: true
+ type: "string"
+ responses:
+ 200:
+ description: "Function Summary"
+ schema:
+ $ref: "#/definitions/FunctionListEntry"
+ 404:
+ description: "Not Found"
+ 500:
+ description: "Internal Server Error"
+ x-swagger-router-controller: "swagger_server.controllers.default_controller"
+ post:
+ summary: "Invoke a defined function"
+ operationId: "function_function_name_post"
+ consumes:
+ - "application/json"
+ - "text/plain"
+ parameters:
+ - name: "functionName"
+ in: "path"
+ description: "Function name"
+ required: true
+ type: "string"
+ - in: "body"
+ name: "input"
+ description: "(Optional) data to pass to function"
+ required: false
+ schema:
+ type: "string"
+ format: "binary"
+ example: "{\"hello\": \"world\"}"
+ responses:
+ 200:
+ description: "Value returned from function"
+ 404:
+ description: "Not Found"
+ 500:
+ description: "Internal server error"
+ x-swagger-router-controller: "swagger_server.controllers.default_controller"
+securityDefinitions:
+ basicAuth:
+ type: "basic"
+definitions:
+ DeleteFunctionRequest:
+ type: "object"
+ required:
+ - "functionName"
+ properties:
+ functionName:
+ type: "string"
+ example: "nodeinfo"
+ description: "Name of deployed function"
+ example:
+ functionName: "nodeinfo"
+ FunctionDefinition:
+ type: "object"
+ required:
+ - "image"
+ - "service"
+ properties:
+ service:
+ type: "string"
+ example: "nodeinfo"
+ description: "Name of deployed function"
+ network:
+ type: "string"
+ example: "func_functions"
+ description: "Docker swarm network, usually func_functions"
+ image:
+ type: "string"
+ example: "functions/nodeinfo:latest"
+ description: "Docker image in accessible registry"
+ envProcess:
+ type: "string"
+ example: "node main.js"
+ description: "Process for watchdog to fork"
+ envVars:
+ type: "object"
+ description: "Overrides to environmental variables"
+ additionalProperties:
+ type: "string"
+ constraints:
+ type: "array"
+ items:
+ type: "string"
+ example: "node.platform.os == linux"
+ description: "Constraints are specific to OpenFaaS Provider"
+ labels:
+ type: "array"
+ description: "An array of labels used by the back-end for making scheduling\
+ \ or routing decisions"
+ items:
+ type: "string"
+ annotations:
+ type: "array"
+ description: "An array of annotations used by the back-end for management,\
+ \ orchestration, events and build tasks"
+ items:
+ type: "string"
+ secrets:
+ type: "array"
+ items:
+ type: "string"
+ example: "secret-name-1"
+ description: "An array of names of secrets that are required to be loaded\
+ \ from the Docker Swarm."
+ registryAuth:
+ type: "string"
+ example: "dXNlcjpwYXNzd29yZA=="
+ description: "Private registry base64-encoded basic auth (as present in ~/.docker/config.json)"
+ limits:
+ $ref: "#/definitions/FunctionDefinition_limits"
+ requests:
+ $ref: "#/definitions/FunctionDefinition_limits"
+ example:
+ image: "functions/nodeinfo:latest"
+ envProcess: "node main.js"
+ service: "nodeinfo"
+ envVars:
+ key: "envVars"
+ annotations:
+ - "annotations"
+ - "annotations"
+ registryAuth: "dXNlcjpwYXNzd29yZA=="
+ requests:
+ memory: "128M"
+ cpu: "0.01"
+ constraints:
+ - "node.platform.os == linux"
+ - "node.platform.os == linux"
+ secrets:
+ - "secret-name-1"
+ - "secret-name-1"
+ limits:
+ memory: "128M"
+ cpu: "0.01"
+ network: "func_functions"
+ labels:
+ - "labels"
+ - "labels"
+ FunctionListEntry:
+ type: "object"
+ required:
+ - "availableReplicas"
+ - "envProcess"
+ - "image"
+ - "invocationCount"
+ - "labels"
+ - "name"
+ - "replicas"
+ properties:
+ name:
+ type: "string"
+ example: "nodeinfo"
+ description: "The name of the function"
+ image:
+ type: "string"
+ example: "functions/nodeinfo:latest"
+ description: "The fully qualified docker image name of the function"
+ invocationCount:
+ type: "number"
+ format: "integer"
+ example: 1337
+ description: "The amount of invocations for the specified function"
+ replicas:
+ type: "number"
+ format: "integer"
+ example: 2
+ description: "The current minimal ammount of replicas"
+ availableReplicas:
+ type: "number"
+ format: "integer"
+ example: 2
+ description: "The current available amount of replicas"
+ envProcess:
+ type: "string"
+ example: "node main.js"
+ description: "Process for watchdog to fork"
+ labels:
+ type: "object"
+ additionalProperties:
+ type: "string"
+ annotations:
+ type: "object"
+ additionalProperties:
+ type: "string"
+ example:
+ image: "functions/nodeinfo:latest"
+ envProcess: "node main.js"
+ replicas: 2
+ name: "nodeinfo"
+ invocationCount: 1337
+ annotations:
+ key: "annotations"
+ availableReplicas: 2
+ labels:
+ key: "labels"
+ FunctionDefinition_limits:
+ properties:
+ memory:
+ type: "string"
+ example: "128M"
+ cpu:
+ type: "string"
+ example: "0.01"
+ example:
+ memory: "128M"
+ cpu: "0.01"
+externalDocs:
+ description: "More documentation available on Github"
+ url: "https://github.com/grycap/oscar"
diff --git a/swagger_server/util.py b/swagger_server/util.py
new file mode 100644
index 00000000..527d1424
--- /dev/null
+++ b/swagger_server/util.py
@@ -0,0 +1,141 @@
+import datetime
+
+import six
+import typing
+
+
+def _deserialize(data, klass):
+ """Deserializes dict, list, str into an object.
+
+ :param data: dict, list or str.
+ :param klass: class literal, or string of class name.
+
+ :return: object.
+ """
+ if data is None:
+ return None
+
+ if klass in six.integer_types or klass in (float, str, bool):
+ return _deserialize_primitive(data, klass)
+ elif klass == object:
+ return _deserialize_object(data)
+ elif klass == datetime.date:
+ return deserialize_date(data)
+ elif klass == datetime.datetime:
+ return deserialize_datetime(data)
+ elif type(klass) == typing.GenericMeta:
+ if klass.__extra__ == list:
+ return _deserialize_list(data, klass.__args__[0])
+ if klass.__extra__ == dict:
+ return _deserialize_dict(data, klass.__args__[1])
+ else:
+ return deserialize_model(data, klass)
+
+
+def _deserialize_primitive(data, klass):
+ """Deserializes to primitive type.
+
+ :param data: data to deserialize.
+ :param klass: class literal.
+
+ :return: int, long, float, str, bool.
+ :rtype: int | long | float | str | bool
+ """
+ try:
+ value = klass(data)
+ except UnicodeEncodeError:
+ value = six.u(data)
+ except TypeError:
+ value = data
+ return value
+
+
+def _deserialize_object(value):
+ """Return a original value.
+
+ :return: object.
+ """
+ return value
+
+
+def deserialize_date(string):
+ """Deserializes string to date.
+
+ :param string: str.
+ :type string: str
+ :return: date.
+ :rtype: date
+ """
+ try:
+ from dateutil.parser import parse
+ return parse(string).date()
+ except ImportError:
+ return string
+
+
+def deserialize_datetime(string):
+ """Deserializes string to datetime.
+
+ The string should be in iso8601 datetime format.
+
+ :param string: str.
+ :type string: str
+ :return: datetime.
+ :rtype: datetime
+ """
+ try:
+ from dateutil.parser import parse
+ return parse(string)
+ except ImportError:
+ return string
+
+
+def deserialize_model(data, klass):
+ """Deserializes list or dict to model.
+
+ :param data: dict, list.
+ :type data: dict | list
+ :param klass: class literal.
+ :return: model object.
+ """
+ instance = klass()
+
+ if not instance.swagger_types:
+ return data
+
+ for attr, attr_type in six.iteritems(instance.swagger_types):
+ if data is not None \
+ and instance.attribute_map[attr] in data \
+ and isinstance(data, (list, dict)):
+ value = data[instance.attribute_map[attr]]
+ setattr(instance, attr, _deserialize(value, attr_type))
+
+ return instance
+
+
+def _deserialize_list(data, boxed_type):
+ """Deserializes a list and its elements.
+
+ :param data: list to deserialize.
+ :type data: list
+ :param boxed_type: class literal.
+
+ :return: deserialized list.
+ :rtype: list
+ """
+ return [_deserialize(sub_data, boxed_type)
+ for sub_data in data]
+
+
+def _deserialize_dict(data, boxed_type):
+ """Deserializes a dict and its elements.
+
+ :param data: dict to deserialize.
+ :type data: dict
+ :param boxed_type: class literal.
+
+ :return: deserialized dict.
+ :rtype: dict
+ """
+ return {k: _deserialize(v, boxed_type)
+ for k, v in six.iteritems(data)}