Skip to content
This repository was archived by the owner on Nov 5, 2022. It is now read-only.

Commit b46e2cd

Browse files
Opencdms cloud (#51)
* add security scheme to climsoft_app * add oauth2 password rewuest form to swagger * remove unnecessary files * refactor deployment code * cleanup and screenshots * update readme * minor refactor * adapt changes with opencdms-cloud * refactor docker compose for prod
1 parent c8d4d97 commit b46e2cd

File tree

7 files changed

+192
-27
lines changed

7 files changed

+192
-27
lines changed

.github/workflows/deploy_stable.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,22 @@ jobs:
2020
HOST_FQDN: ${{secrets.STABLE_HOST_FQDN}}
2121
AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}}
2222
AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}}
23-
AUTH_ENABLED: "True"
23+
AUTH_ENABLED: true
24+
CLIMSOFT_API_ENABLED: true
25+
MCH_API_ENABLED: true
26+
SURFACE_API_ENABLED: true
27+
PYGEOAPI_ENABLED: true
2428

2529
run: |
2630
echo "$PRIVATE_KEY" > private_key && chmod 600 private_key
27-
ssh -o StrictHostKeyChecking=no -o SendEnv=AUTH_ENABLED -o SendEnv=HOST_FQDN -o SendEnv=AWS_ACCESS_KEY_ID -o SendEnv=AWS_SECRET_ACCESS_KEY -i private_key ${USERNAME}@${HOSTNAME} '
31+
ssh -o StrictHostKeyChecking=no -o SendEnv=AUTH_ENABLED -o SendEnv=HOST_FQDN -o SendEnv=AWS_ACCESS_KEY_ID -o SendEnv=AWS_SECRET_ACCESS_KEY -o SendEnv=CLIMSOFT_API_ENABLED -o SendEnv=SURFACE_API_ENABLED -o SendEnv=MCH_API_ENABLED -o SendEnv=PYGEOAPI_ENABLED -i private_key ${USERNAME}@${HOSTNAME} '
2832
cd /home/ubuntu/opencdms-test-data
2933
git pull origin main
3034
cd /home/ubuntu/opencdms-api
3135
git pull origin main
32-
docker-compose down -v --remove-orphans
36+
docker-compose -f docker-compose.prod.yml down -v --remove-orphans
3337
docker-compose -f ../opencdms-test-data/docker-compose.yml down -v --remove-orphans
3438
docker-compose -f ../opencdms-test-data/docker-compose.yml up -d postgresql mysql oracle
3539
sleep 15
36-
docker-compose up -d --build
40+
docker-compose -f docker-compose.prod.yml up -d --build
3741
'

Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ RUN pip install -r requirements.txt
2727

2828
COPY ./scripts ./scripts
2929
COPY entrypoint.sh ./entrypoint.sh
30-
COPY init_climsoft_db.py ./init_climsoft_db.py
3130
COPY mch.dbn ./mch.dbn
3231
COPY MCHtablasycampos.def ./MCHtablasycampos.def
3332

docker-compose.prod.yml

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
version: "3"
2+
3+
services:
4+
opencdms_api:
5+
build:
6+
context: .
7+
dockerfile: Dockerfile
8+
container_name: opencdms_api
9+
ports:
10+
- "5070:5000"
11+
env_file:
12+
- .env
13+
environment:
14+
- PYGEOAPI_CONFIG=/code/pygeoapi-config.yml
15+
- PYGEOAPI_OPENAPI=/code/pygeoapi-openapi.yml
16+
- PYTHONPATH=/code/surface/api
17+
- CLIMSOFT_DATABASE_URI=mysql+mysqldb://root:password@mysql:3306/mariadb_climsoft_test_db_v4
18+
- CLIMSOFT_SECRET_KEY=climsoft-secret-key
19+
- AUTH_DB_URI=postgresql+psycopg2://dba:dba@opencdms_surface_db:5432/surface
20+
- SURFACE_DB_NAME=surface
21+
- SURFACE_DB_USER=dba
22+
- SURFACE_DB_PASSWORD=dba
23+
- SURFACE_DB_HOST=opencdms_surfacedb
24+
- SURFACE_DB_PORT=5432
25+
- MCH_DB_PORT=3306
26+
- MCH_DB_HOST=mch-english
27+
- MCH_DB_NAME=mch
28+
- MCH_DB_PASSWORD=password
29+
- MCH_DB_USER=root
30+
- APP_SECRET=app-secret
31+
- SURFACE_SECRET_KEY=surface-secret-key
32+
- SECRET_KEY=secret-key
33+
- TIMESCALEDB_TELEMETRY=off
34+
- PGDATA=/var/lib/postgresql/data/pgdata
35+
- SURFACE_DATA_DIR=/home/surface/surface_data/shared
36+
- SURFACE_DB_ENGINE=django.contrib.gis.db.backends.postgis
37+
- SURFACE_BROKER_URL=redis://redis:6379/0
38+
- SURFACE_DJANGO_DEBUG=False
39+
- LOGIN_REDIRECT_URL=/wx/stations/map/
40+
- LOGOUT_REDIRECT_URL=/accounts/login/
41+
- LRGS_EXECUTABLE_PATH=/surface/LrgsClient/bin/getDcpMessages
42+
- LRGS_SERVER_HOST=lrgseddn1.cr.usgs.gov
43+
- LRGS_SERVER_PORT=16003
44+
- LRGS_USER=belnms
45+
- LRGS_PASSWORD=BWSNlrgs2016!
46+
- LRGS_CS_FILE_PATH=/data/search_parameters.cs
47+
- LRGS_MAX_INTERVAL=719
48+
- ENTL_PRIMARY_SERVER_HOST=107.23.152.248
49+
- ENTL_PRIMARY_SERVER_PORT=2324
50+
- ENTL_SECONDARY_SERVER_HOST=107.23.135.182
51+
- ENTL_SECONDARY_SERVER_PORT=2324
52+
- ENTL_PARTNER_ID=2B6FDADE-CA7F-443A-AD79-2FF21CEF4857
53+
- EMAIL_HOST=smtp.gmail.com
54+
- EMAIL_HOST_USER=test_email_host
55+
- EMAIL_HOST_PASSWORD=test_email_password
56+
- EMAIL_PORT=587
57+
- TIMEZONE_NAME=America/Belize
58+
- TIMEZONE_OFFSET=-360
59+
- INMET_HOURLY_DATA_URL=
60+
- INMET_DAILY_DATA_BASE_PATH=
61+
- MAP_LATITUDE=17.302212
62+
- MAP_LONGITUDE=-88.429595
63+
- MAP_ZOOM=8
64+
- SPATIAL_ANALYSIS_INITIAL_LATITUDE=15.8469375676
65+
- SPATIAL_ANALYSIS_INITIAL_LONGITUDE=-89.227
66+
- SPATIAL_ANALYSIS_FINAL_LATITUDE=18.5299822047
67+
- SPATIAL_ANALYSIS_FINAL_LONGITUDE=-87.485
68+
- SPATIAL_ANALYSIS_SHAPE_FILE_PATH=/surface/static/images/blz_shape.png
69+
- STATION_MAP_WIND_SPEED_ID=51
70+
- STATION_MAP_WIND_GUST_ID=53
71+
- STATION_MAP_WIND_DIRECTION_ID=56
72+
- STATION_MAP_TEMP_MAX_ID=16
73+
- STATION_MAP_TEMP_MIN_ID=14
74+
- STATION_MAP_TEMP_AVG_ID=10
75+
- STATION_MAP_ATM_PRESSURE_ID=60
76+
- STATION_MAP_PRECIPITATION_ID=0
77+
- STATION_MAP_RELATIVE_HUMIDITY_ID=30
78+
- STATION_MAP_SOLAR_RADIATION_ID=72
79+
- STATION_MAP_FILTER_WATERSHED=1
80+
- STATION_MAP_FILTER_REGION=1
81+
- STATION_MAP_FILTER_COMMUNICATION=1
82+
- SURFACE_API_ENABLED=$SURFACE_API_ENABLED
83+
- CLIMSOFT_API_ENABLED=$CLIMSOFT_API_ENABLED
84+
- MCH_API_ENABLED=$MCH_API_ENABLED
85+
- PYGEOAPI_ENABLED=$PYGEOAPI_ENABLED
86+
- DEFAULT_USERNAME=admin
87+
- DEFAULT_PASSWORD=password123
88+
- HOST_FQDN=$HOST_FQDN
89+
- CLIMSOFT_AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
90+
- CLIMSOFT_AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
91+
- AUTH_ENABLED=true
92+
depends_on:
93+
- opencdms_surfacedb
94+
volumes:
95+
- ./src:/code/src
96+
- ./climsoft_uploads:/climsoft_uploads
97+
labels:
98+
- "traefik.enable=true"
99+
- "traefik.http.routers.fastapi.rule=Host(`$HOST_FQDN`)"
100+
- "traefik.http.routers.fastapi.tls=true"
101+
- "traefik.http.routers.fastapi.tls.certresolver=letsencrypt"
102+
networks:
103+
- opencdms-test-data_opencdms
104+
command:
105+
[
106+
"uvicorn",
107+
"src.opencdms_api.main:app",
108+
"--host",
109+
"0.0.0.0",
110+
"--port",
111+
"5000",
112+
"--reload",
113+
"--proxy-headers",
114+
]
115+
116+
opencdms_surfacedb:
117+
image: timescale/timescaledb-postgis:2.3.0-pg13
118+
container_name: opencdms_surface_db
119+
volumes:
120+
- opencdms_surface_data:/var/lib/postgresql/data
121+
ports:
122+
- "65432:5432"
123+
environment:
124+
- POSTGRES_PASSWORD=dba
125+
- POSTGRES_DB=surface
126+
- POSTGRES_USER=dba
127+
logging:
128+
driver: "json-file"
129+
options:
130+
max-size: "1M"
131+
max-file: "10"
132+
networks:
133+
- opencdms-test-data_opencdms
134+
135+
traefik:
136+
image: traefik:latest
137+
ports:
138+
- "80:80"
139+
- "443:443"
140+
volumes:
141+
- "/var/run/docker.sock:/var/run/docker.sock:ro"
142+
- "$PWD/traefik/traefik.toml:/etc/traefik/traefik.toml"
143+
144+
volumes:
145+
opencdms_surface_data:
146+
147+
networks:
148+
opencdms-test-data_opencdms:
149+
external: true
150+
driver: bridge

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ services:
8282
- SURFACE_API_ENABLED=true
8383
- CLIMSOFT_API_ENABLED=true
8484
- MCH_API_ENABLED=true
85+
- PYGEOAPI_ENABLED=true
8586
- DEFAULT_USERNAME=admin
8687
- DEFAULT_PASSWORD=password123
8788
- HOST_FQDN=$HOST_FQDN

src/opencdms_api/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class Settings(BaseSettings):
1818
SURFACE_API_ENABLED: bool
1919
CLIMSOFT_API_ENABLED: bool
2020
MCH_API_ENABLED: bool
21+
PYGEOAPI_ENABLED: bool
2122

2223
DEFAULT_USERNAME: str
2324
DEFAULT_PASSWORD: str

src/opencdms_api/main.py

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@
2525
from opencdms.models.climsoft import v4_1_1_core as climsoft_models
2626
from src.opencdms_api.middleware import get_authorized_climsoft_user
2727
from climsoft_api.api import api_routers
28-
from fastapi.security import OAuth2PasswordBearer
29-
30-
31-
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth")
3228

3329

3430
# load controllers
@@ -46,26 +42,39 @@ def get_app():
4642
)
4743
climsoft_app = get_climsoft_app()
4844

49-
if settings.SURFACE_API_ENABLED is True:
45+
if settings.SURFACE_API_ENABLED:
5046
surface_wsgi_app = WSGIMiddleware(surface_application)
5147
app.mount("/surface", surface_wsgi_app)
5248

53-
if settings.MCH_API_ENABLED is True:
49+
if settings.MCH_API_ENABLED:
5450
mch_wsgi_app = WSGIMiddleware(mch_api_application)
55-
app.mount("/mch", AuthMiddleWare(mch_wsgi_app))
56-
57-
if settings.CLIMSOFT_API_ENABLED is True:
58-
for r in api_routers:
59-
climsoft_app.include_router(
60-
**r.dict(),
61-
dependencies=[
62-
Depends(oauth2_scheme)
63-
]
64-
)
51+
if settings.AUTH_ENABLED:
52+
app.mount("/mch", AuthMiddleWare(mch_wsgi_app))
53+
else:
54+
app.mount("/mch", mch_wsgi_app)
55+
56+
if settings.CLIMSOFT_API_ENABLED:
57+
if settings.AUTH_ENABLED:
58+
for r in api_routers:
59+
climsoft_app.include_router(
60+
**r.dict(),
61+
dependencies=[
62+
Depends(get_authorized_climsoft_user)
63+
]
64+
)
65+
else:
66+
for r in api_routers:
67+
climsoft_app.include_router(
68+
**r.dict()
69+
)
6570
app.mount("/climsoft", climsoft_app)
6671

67-
pygeoapi_wsgi_app = WSGIMiddleware(pygeoapi_app)
68-
app.mount("/pygeoapi", AuthMiddleWare(pygeoapi_wsgi_app))
72+
if settings.PYGEOAPI_ENABLED:
73+
pygeoapi_wsgi_app = WSGIMiddleware(pygeoapi_app)
74+
if settings.AUTH_ENABLED:
75+
app.mount("/pygeoapi", AuthMiddleWare(pygeoapi_wsgi_app))
76+
else:
77+
app.mount("/pygeoapi", pygeoapi_wsgi_app)
6978

7079
app.include_router(router)
7180

src/opencdms_api/middleware.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
from src.opencdms_api.schema import CurrentUserSchema
1616
from opencdms.models.climsoft import v4_1_1_core as climsoft_models
1717
from fastapi import Header, Depends
18+
from fastapi.security import OAuth2PasswordBearer
19+
20+
21+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth")
1822

1923

2024
def get_user(username: str) -> Optional[CurrentUserSchema]:
@@ -121,11 +125,8 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send):
121125

122126
def get_authorized_climsoft_user(
123127
request: Request,
124-
authorization: str = Header(None)
128+
token: str = Depends(oauth2_scheme)
125129
):
126-
scheme, token = get_authorization_scheme_param(authorization)
127-
if scheme.lower() != "bearer":
128-
raise HTTPException(401, "Invalid authorization header scheme")
129130
try:
130131
claims = jwt.decode(token, settings.SURFACE_SECRET_KEY)
131132
except JWTError:

0 commit comments

Comments
 (0)