Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nersc deployment adaptations (Auth, Environment variables) #124

Merged
merged 8 commits into from
Oct 4, 2023
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
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ pri-venv
data/

env
*env/
*.hdf5
*.db

.theia/
*.tiff
*.tif

.env
config.py
.env
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ and
pip install -r requirements-dev.txt
```

2. Configure a connection to the Tiled server via a `.env` file with the following environment variables:
2. Set environment variables via a `.env` file to configure a connection to the Tiled server, differentiate between local testing and development mode and set a user and password for basic autherization:

```
TILED_URI='https://mlex-segmentation.als.lbl.gov'
API_KEY=<key-provided-on-request>
TILED_URI='https://tiled-seg.als.lbl.gov'
TILED_API_KEY=<key-provided-on-request>
DASH_DEPLOYMENT_LOC='Local'
MODE='dev'
```

Expand All @@ -42,12 +43,21 @@ python app.py
Developers may also choose to set up a local Tiled server with access to minimal datasets (eg. in the case that the remote server is down).

To start local tiled connection:
1. Add `SERVE_LOCALLY=True` flag to `.env` file (or to your environmental variables)
1. Add `TILED_DEPLOYMENT_LOC="Local"` flag to `.env` file (or to your environmental variables)
2. Start the app once, which will create `data/` directory and download 2 sample projects with 2 images each.
3. Open a second terminal and run `tiled serve directory --public data`.
3. Open a second terminal and run `/tiled_serve_dir.sh`.

The app will now connect to the local tiled server.

### Deployment elsewhere

For deployment elsewhere add a user name and password to the environment file and remove `DASH_DEPLOYMENT_LOC = "Local"`. This protect access to the application with basic authentication:

```
USER_NAME=<to-be-specified-per-deployment>
USER_PASSWORD=<to-be-specified-per-deployment>
```

# Copyright
MLExchange Copyright (c) 2023, The Regents of the University of California, through Lawrence Berkeley National Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved.

Expand Down
15 changes: 15 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import os

import dash_auth
import dash_mantine_components as dmc
from dash import Dash, dcc

Expand All @@ -7,9 +10,21 @@
from components.control_bar import layout as control_bar_layout
from components.image_viewer import layout as image_viewer_layout

USER_NAME = os.getenv("USER_NAME")
USER_PASSWORD = os.getenv("USER_PASSWORD")

VALID_USER_NAME_PASSWORD_PAIRS = {USER_NAME: USER_PASSWORD}

app = Dash(__name__)
server = app.server

# Set single user name password pair if deployment isn't
auth = (
dash_auth.BasicAuth(app, VALID_USER_NAME_PASSWORD_PAIRS)
if os.getenv("DASH_DEPLOYMENT_LOC", "") != "Local"
else None
)

app.layout = dmc.MantineProvider(
theme={"colorScheme": "light"},
children=[
Expand Down
4 changes: 2 additions & 2 deletions callbacks/control_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
)

# TODO - temporary local file path and user for annotation saving and exporting
EXPORT_FILE_PATH = "data/exported_annotation_data.json"
USER_NAME = "user1"
EXPORT_FILE_PATH = os.getenv("EXPORT_FILE_PATH", "data/exported_annotation_data.json")
USER_NAME = os.getenv("USER_NAME", "user1")

# Create an empty file if it doesn't exist
if not os.path.exists(EXPORT_FILE_PATH):
Expand Down
3 changes: 2 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ services:
command: 'gunicorn -b 0.0.0.0:8075 --reload app:server'
environment:
TILED_URI: '${TILED_URI}'
API_KEY: '${API_KEY}'
TILED_API_KEY: '${TILED_API_KEY}'
volumes:
- ./app.py:/app/app.py
- ./constants.py:/app/constants.py
- ./callbacks:/app/callbacks
- ./components:/app/components
- ./utils:/app/utils
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ svgpathtools
matplotlib
scipy
dash-extensions==1.0.1
dash-bootstrap-components==1.5.0
dash-bootstrap-components==1.5.0
dash_auth==2.0.0
4 changes: 4 additions & 0 deletions tiled_serve_dir.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash
source .env
export TILED_SINGLE_USER_API_KEY=$TILED_API_KEY
tiled serve directory data
8 changes: 4 additions & 4 deletions utils/data_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,17 @@ def save_annotations_data(global_store, all_annotations, project_name):
load_dotenv()

TILED_URI = os.getenv("TILED_URI")
API_KEY = os.getenv("API_KEY")
TILED_API_KEY = os.getenv("TILED_API_KEY")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm testing this against our local Tiled server as well and get surprising behaviour with this change. My Python code throws an authentication error:

    raise ClientError(message, exc.request, exc.response) from exc
tiled.client.utils.ClientError: 401: Invalid API key http://localhost:8000/api/v1/metadata/

And the local Tiled server blocks my requests:

INFO:     127.0.0.1:62131 - "GET /api/v1/metadata/clay_testZMQ HTTP/1.1" 401 Unauthorized

This seems to be only the case if this variable is called TILED_API_KEY. Not a problem, for example, if I change this to TLD_API_KEY. Wondering if this is because Tiled is trying to be too smart under the hood and something in the local client detects any env var with this name and tries to apply it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, you are right. My current understanding of what causes this error is as follows:

The client picks up on TILED_API_KEY being set as an environment variables and then uses that as an API key to authenticate, see [tiled/client/context.py#L79].(https://github.com/bluesky/tiled/blob/7566d0f2d61cb0477bf187b33e94d7449358c4e5/tiled/client/context.py#L79)

Our local server started with tiled serve directory --public data is in principle accessible without a key (we are allowed to read data without having an api_key in the request), but it does generate a key on startup (which would be needed for writing data). Our requests having a different key then causes the error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see 2 main ways to address this:

  1. Rename the TILED_API_KEY environment variable to something else, or
  2. Start our local tiled server with the api key from the environment, such that we get a match again.

Keeping in mind that we may have this application run in different deployment environments and hooked up to different Tiled servers, I think I would like to stay away from baking in more semantics into the variable. In the latest update, I thus added a script that starts the local server with the TILED_API_KEY from the environment file by setting the TILED_SINGLE_API_KEY variable that the server makes use of (if set).

Let me know if that works for your test workflow @hannahker.


if os.getenv("SERVE_LOCALLY", False):
print("To run a Tiled server locally run `tiled serve directory --public data`.")
if os.getenv("TILED_DEPLOYMENT_LOC", "") == "Local":
print("To run a Tiled server locally run the bash script `./tiled_serve_dir.sh`.")
print("This requires to additionally install the server components of Tiled with:")
print('`pip install "tiled[server]"`')
DEV_download_google_sample_data()
client = from_uri("http://localhost:8000")
data = client
else:
client = from_uri(TILED_URI, api_key=API_KEY, timeout=httpx.Timeout(30.0))
client = from_uri(TILED_URI, api_key=TILED_API_KEY, timeout=httpx.Timeout(30.0))
data = client["reconstruction"]


Expand Down
Loading