Skip to content
Merged
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
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ USER user

COPY optimizerapi/ /code

ENV FLASK_ENV=production

ENV PATH=/opt/venv/bin:${PATH}

CMD [ "python", "./server.py" ]
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,30 @@ Alternatively the project can be build and run with the following commands:
python optimizerapi/server.py

Now open [http://localhost:9090/v1.0/ui/](http://localhost:9090/v1.0/ui/) in a browser to explore the API through Swagger UI

# Running tests

Unit tetsts are located in the "tests" folder and can be run witht the following command

python -m pytest

# Building docker container

docker build -t process-optimizer-api .
# Obtain encryption key

Run server once and extract a fresh encryption key from the logs.

python optimizerapi/server.py

or using docker

docker run --rm -it process-optimizer-api
# Running in production

Running using python

FLASK_ENV=production PICKLE_KEY=<key from previous step> python optimizerapi/server.py

or use docker

docker run -d --name process-optimizer-api --env PICKLE_KEY=<key from previous step> -p 9090:9090 process-optimizer-api:latest
2 changes: 2 additions & 0 deletions optimizerapi/openapi/specification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ components:
result:
type: object
properties:
pickled:
type: string
next:
type: array
items:
Expand Down
9 changes: 5 additions & 4 deletions optimizerapi/optimizer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import codecs
import pickle
import json
from json_tricks import dumps
from ProcessOptimizer import Optimizer, expected_minimum
Expand All @@ -10,6 +8,8 @@
import base64
import io
from numbers import Number
from securepickle import pickleToString, unpickleFromString, get_crypto

import numpy
numpy.random.seed(42)
"""ProcessOptimizer web request handler
Expand Down Expand Up @@ -110,9 +110,10 @@ def processResult(result, optimizer, dimensions, cfg, data, space):
addPlot(response["plots"], "convergence")

plot_objective(result, dimensions=dimensions, usepartialdependence=False)
addPlot(response["plots"], "objective", debug=True)
addPlot(response["plots"], "objective")

print(str(response))
prettyResult["pickled"] = pickleToString(result, get_crypto())
# print(str(response))
return response

def addPlot(result, id="generic", close=True, debug=False):
Expand Down
2 changes: 2 additions & 0 deletions optimizerapi/securepickle/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .pickler import pickleToString, unpickleFromString
from .secure import get_crypto
11 changes: 11 additions & 0 deletions optimizerapi/securepickle/pickler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import codecs
import pickle

def pickleToString(obj, crypto):
pickled = codecs.encode(crypto.encrypt(pickle.dumps(obj)), "base64").decode()
return pickled

def unpickleFromString(pickled, crypto):
unpickled = pickle.loads(crypto.decrypt(codecs.decode(pickled.encode(), "base64")))
return unpickled

11 changes: 11 additions & 0 deletions optimizerapi/securepickle/secure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from cryptography.fernet import Fernet
import os

def get_crypto(key=None):
if key == None: key = os.getenv("PICKLE_KEY", None)
if key == None:
print("No key found, generating new key")
key = Fernet.generate_key()
os.environ["PICKLE_KEY"] = key.decode("utf-8")
print("To reuse key for future server runs, set environment variable PICKLE_KEY=" + os.environ["PICKLE_KEY"])
return Fernet(key)
11 changes: 10 additions & 1 deletion optimizerapi/server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import os
import connexion
from securepickle import get_crypto
from waitress import serve

if __name__ == '__main__':
# Initialize crypto
get_crypto()
app = connexion.FlaskApp(__name__, port=9090, specification_dir='./openapi/')
app.add_api('specification.yml', arguments={'title': 'Hello World Example'})
app.run()
if os.getenv("FLASK_ENV", "development") == "development":
os.environ["FLASK_ENV"] = "development"
app.run()
else:
serve(app, listen='*:9090')
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ connexion==2.7.0
connexion[swagger-ui]
Flask==1.1.2
ProcessOptimizer==0.6.1
json-tricks==3.15.5
json-tricks==3.15.5
cryptography==3.4.7
waitress==2.0.0
15 changes: 15 additions & 0 deletions tests/test_securepickle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from optimizerapi.securepickle import pickleToString, unpickleFromString, get_crypto

def test_pickleToString():
f = get_crypto()
encoded = pickleToString("myString", f)
assert encoded != "myString"

def test_unpickleFromString():
f = get_crypto()
encoded = pickleToString("myString", f)
decoded = unpickleFromString(encoded, f)
assert decoded == "myString"