Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"python.testing.unittestEnabled": false,
"python.testing.nosetestsEnabled": false,
"python.testing.pytestEnabled": true,
"python.linting.pycodestyleEnabled": true
"python.linting.pycodestyleEnabled": true,
"python.pythonPath": "c:\\Users\\ogolovatyi\\.conda\\envs\\Python 3.7 (tornado 6)\\python.exe"
}
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## v1.2.0

### Improvements

- Added support for Rserve protocol.

## v1.1.0

### Improvements
Expand Down
103 changes: 38 additions & 65 deletions docs/server-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

- [Custom Settings](#custom-settings)
* [Configuration File Content](#configuration-file-content)
* [Evaluation Engines](#evaluation-engines)
+ [Python Evaluation Engine](#python-evaluation-engine)
+ [Rserve Evaluation Engine](#rserve-evaluation-engine)
* [Configuration File Example](#configuration-file-example)
- [Configuring HTTP vs HTTPS](#configuring-http-vs-https)
- [Authentication](#authentication)
Expand All @@ -14,6 +17,7 @@
* [Adding an Account](#adding-an-account)
* [Updating an Account](#updating-an-account)
* [Deleting an Account](#deleting-an-account)
* [Endpoint Security](#endpoint-security)
- [Logging](#logging)
* [Request Context Logging](#request-context-logging)

Expand Down Expand Up @@ -91,77 +95,46 @@ at [`logging.config` documentation page](https://docs.python.org/3.6/library/log
value - `30`. This timeout does not apply when evaluating models either
through the `/query` method, or using the `tabpy.query(...)` syntax with
the `/evaluate` method.
- `TABPY_EVALUATE_WITH` - evaluation engine for user scripts. Supported
values are `Python` and `Rserve`. For specific configuration and other
details on each evaluation engine see [Evaluation Engines](#evaluation-engines)
section. Default value - `Python`.

### Evaluation Engines

TabPy supports evaluation user scripts with different evaluation engines.
The engine can be specified with `TABPY_EVALUATE_WITH` configuration parameter.
By default `Python` evaluation engine is used.

#### Python Evaluation Engine

User scripts are executed in the same Python instance where TabPy is running.
No additional configuration parameters are needed for the engine (in
`[TabPy]` section):

- `EXTSVC_HOST` - Rserve host.
- `EXTSVC_PORT` - Rserve port.

Current limitations:

- Authentication is not supported.

#### Rserve Evaluation Engine

TabPy forwards data and user script to specified
[Rserve](https://www.rforge.net/Rserve/) instance.

There are some additional configuration parameters needed for the engine:

- Authentication is not supported.

### Configuration File Example

**Note:** _Always use absolute paths for the configuration paths
settings._

```ini
[TabPy]
# TABPY_QUERY_OBJECT_PATH = /tmp/query_objects
# TABPY_PORT = 9004
# TABPY_STATE_PATH = <package-path>/tabpy/tabpy_server

# Where static pages live
# TABPY_STATIC_PATH = <package-path>/tabpy/tabpy_server/static

# For how to configure TabPy authentication read
# docs/server-config.md.
# TABPY_PWD_FILE = /path/to/password/file.txt

# To set up secure TabPy uncomment and modify the following lines.
# Note only PEM-encoded x509 certificates are supported.
# TABPY_TRANSFER_PROTOCOL = https
# TABPY_CERTIFICATE_FILE = /path/to/certificate/file.crt
# TABPY_KEY_FILE = /path/to/key/file.key

# Log additional request details including caller IP, full URL, client
# end user info if provided.
# TABPY_LOG_DETAILS = true

# Limit request size (in Mb) - any request which size exceeds
# specified amount will be rejected by TabPy.
# Default value is 100 Mb.
# TABPY_MAX_REQUEST_SIZE_MB = 100

# Configure how long a custom script provided to the /evaluate method
# will run before throwing a TimeoutError.
# The value should be a float representing the timeout time in seconds.
# TABPY_EVALUATE_TIMEOUT = 30

[loggers]
keys=root

[handlers]
keys=rootHandler,rotatingFileHandler

[formatters]
keys=rootFormatter

[logger_root]
level=DEBUG
handlers=rootHandler,rotatingFileHandler
qualname=root
propagete=0

[handler_rootHandler]
class=StreamHandler
level=DEBUG
formatter=rootFormatter
args=(sys.stdout,)

[handler_rotatingFileHandler]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=rootFormatter
args=('tabpy_log.log', 'a', 1000000, 5)

[formatter_rootFormatter]
format=%(asctime)s [%(levelname)s] (%(filename)s:%(module)s:%(lineno)d): %(message)s
datefmt=%Y-%m-%d,%H:%M:%S

```
Example file can be found at
[https://github.com/tableau/TabPy/blob/master/tabpy/tabpy_server/common/default.conf](https://github.com/tableau/TabPy/blob/master/tabpy/tabpy_server/common/default.conf).

## Configuring HTTP vs HTTPS

Expand Down
2 changes: 1 addition & 1 deletion docs/tabpy-virtualenv.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ To run TabPy in an Anaconda virtual environment follow the steps:
in a Windows environment*

1. For Windows open `Anaconda Prompt` from the Windows Start menu, for
Linux and Mac run shell.
Linux and Mac run shell.

2. Navigate to your home directory:
1. On Windows run
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def read(fname):
"numpy",
"pandas",
"pyopenssl",
"pyrserve",
"python-dateutil",
"requests",
"scipy",
Expand Down
2 changes: 1 addition & 1 deletion tabpy/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1.0
1.2.0
1 change: 0 additions & 1 deletion tabpy/models/deploy_models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import os
from pathlib import Path
import pip
import platform
import subprocess
import sys
Expand Down
17 changes: 0 additions & 17 deletions tabpy/tabpy_server/app/ConfigParameters.py

This file was deleted.

17 changes: 0 additions & 17 deletions tabpy/tabpy_server/app/SettingsParameters.py

This file was deleted.

53 changes: 32 additions & 21 deletions tabpy/tabpy_server/app/app.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import concurrent.futures
import configparser
import logging
from logging import config
import multiprocessing
import os
import shutil
import signal
import sys
import tabpy.tabpy_server
from tabpy.tabpy import __version__
from tabpy.tabpy_server.app.ConfigParameters import ConfigParameters
from tabpy.tabpy_server.app.SettingsParameters import SettingsParameters
from tabpy.tabpy_server.app.app_parameters import ConfigParameters, SettingsParameters
from tabpy.tabpy_server.app.util import parse_pwd_file
from tabpy.tabpy_server.management.state import TabPyState
from tabpy.tabpy_server.management.util import _get_state_from_file
Expand Down Expand Up @@ -128,17 +125,10 @@ def try_exit(self):
)
logger.info("Done initializing TabPy.")

executor = concurrent.futures.ThreadPoolExecutor(
max_workers=multiprocessing.cpu_count()
)

# initialize Tornado application
_init_asyncio_patch()
application = TabPyTornadoApp(
[
# skip MainHandler to use StaticFileHandler .* page requests and
# default to index.html
# (r"/", MainHandler),
(
self.subdirectory + r"/query/([^/]+)",
QueryPlaneHandler,
Expand All @@ -152,11 +142,7 @@ def try_exit(self):
EndpointHandler,
dict(app=self),
),
(
self.subdirectory + r"/evaluate",
EvaluationPlaneHandler,
dict(executor=executor, app=self),
),
(self.subdirectory + r"/evaluate", EvaluationPlaneHandler, dict(app=self)),
(
self.subdirectory + r"/configurations/endpoint_upload_destination",
UploadDestinationHandler,
Expand Down Expand Up @@ -213,6 +199,31 @@ def _set_parameter(self, parser, settings_key, config_key, default_val, parse_fu
if not key_is_set:
logger.debug(f"Parameter {settings_key} is not set")

def _parse_eval_with_config(self, parser):
"""
Parse parameters specific for evaluation engine.
"""

settings_parameters = []
evaluate_with = self.settings[SettingsParameters.EvaluateWith].lower()

if evaluate_with == "python":
# do nothing, Python evaluation requieres no additional parameters
pass
elif evaluate_with == "rserve":
settings_parameters = [
(SettingsParameters.ExtSvcHost, ConfigParameters.EXTSVC_HOST, None, None),
(SettingsParameters.ExtSvcPort, ConfigParameters.EXTSVC_PORT, None,
parser.getint),
]
else:
msg = f"Unknown evaluation engine '{evaluate_with}'"
logger.critical(msg)
raise RuntimeError(msg)

for setting, parameter, default_val, parse_function in settings_parameters:
self._set_parameter(parser, setting, parameter, default_val, parse_function)

def _parse_config(self, config_file):
"""Provide consistent mechanism for pulling in configuration.

Expand Down Expand Up @@ -274,11 +285,16 @@ def _parse_config(self, config_file):
"false", None),
(SettingsParameters.MaxRequestSizeInMb, ConfigParameters.TABPY_MAX_REQUEST_SIZE_MB,
100, None),
(SettingsParameters.EvaluateWith, ConfigParameters.TABPY_EVALUATE_WITH,
"Python", None),
]

for setting, parameter, default_val, parse_function in settings_parameters:
self._set_parameter(parser, setting, parameter, default_val, parse_function)

# parse evaluation engine specific parameters
self._parse_eval_with_config(parser)

if not os.path.exists(self.settings[SettingsParameters.UploadDir]):
os.makedirs(self.settings[SettingsParameters.UploadDir])

Expand Down Expand Up @@ -340,11 +356,6 @@ def _parse_config(self, config_file):
logger.info(f"Call context logging is {call_context_state}")

def _validate_transfer_protocol_settings(self):
if SettingsParameters.TransferProtocol not in self.settings:
msg = "Missing transfer protocol information."
logger.critical(msg)
raise RuntimeError(msg)

protocol = self.settings[SettingsParameters.TransferProtocol]

if protocol == "http":
Expand Down
42 changes: 42 additions & 0 deletions tabpy/tabpy_server/app/app_parameters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
class ConfigParameters:
"""
Configuration settings names
"""

TABPY_PWD_FILE = "TABPY_PWD_FILE"
TABPY_PORT = "TABPY_PORT"
TABPY_QUERY_OBJECT_PATH = "TABPY_QUERY_OBJECT_PATH"
TABPY_STATE_PATH = "TABPY_STATE_PATH"
TABPY_TRANSFER_PROTOCOL = "TABPY_TRANSFER_PROTOCOL"
TABPY_CERTIFICATE_FILE = "TABPY_CERTIFICATE_FILE"
TABPY_KEY_FILE = "TABPY_KEY_FILE"
TABPY_PWD_FILE = "TABPY_PWD_FILE"
TABPY_LOG_DETAILS = "TABPY_LOG_DETAILS"
TABPY_STATIC_PATH = "TABPY_STATIC_PATH"
TABPY_MAX_REQUEST_SIZE_MB = "TABPY_MAX_REQUEST_SIZE_MB"
TABPY_EVALUATE_TIMEOUT = "TABPY_EVALUATE_TIMEOUT"
TABPY_EVALUATE_WITH = "TABPY_EVALUATE_WITH"
EXTSVC_HOST = "EXTSVC_HOST"
EXTSVC_PORT = "EXTSVC_PORT"


class SettingsParameters:
"""
Application (TabPyApp) settings names
"""

TransferProtocol = "transfer_protocol"
Port = "port"
ServerVersion = "server_version"
UploadDir = "upload_dir"
CertificateFile = "certificate_file"
KeyFile = "key_file"
StateFilePath = "state_file_path"
ApiVersions = "versions"
LogRequestContext = "log_request_context"
StaticPath = "static_path"
MaxRequestSizeInMb = "max_request_size_in_mb"
EvaluateTimeout = "evaluate_timeout"
EvaluateWith = "evaluate_with"
ExtSvcHost = "extsvc_host"
ExtSvcPort = "extsvc_port"
16 changes: 16 additions & 0 deletions tabpy/tabpy_server/common/default.conf
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@
# The value should be a float representing the timeout time in seconds.
# TABPY_EVALUATE_TIMEOUT = 30

# Configure evaluation engine for user scripts.
# Supported values: Python, Rserve.
# Default: Python.
# TABPY_EVALUATE_WITH = Python

# ======================================
# Evaluation engine specific parameters.

# External service host.
# Used by: Rserve
# EXTSVC_HOST = <host>

# External service port.
# Used by: Rserve
# EXTSVC_PORT = <port>

[loggers]
keys=root

Expand Down
2 changes: 0 additions & 2 deletions tabpy/tabpy_server/handlers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from tabpy.tabpy_server.handlers.base_handler import BaseHandler
from tabpy.tabpy_server.handlers.main_handler import MainHandler
from tabpy.tabpy_server.handlers.management_handler import ManagementHandler

from tabpy.tabpy_server.handlers.endpoint_handler import EndpointHandler
from tabpy.tabpy_server.handlers.endpoints_handler import EndpointsHandler
from tabpy.tabpy_server.handlers.evaluation_plane_handler import EvaluationPlaneHandler
Expand Down
Loading