diff --git a/.env b/.env new file mode 100644 index 0000000..9305039 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +SERVER_IMAGE_TAG=2024-08-12--15-15 \ No newline at end of file diff --git a/.env.cognito.template b/.env.cognito.template new file mode 100644 index 0000000..437bd68 --- /dev/null +++ b/.env.cognito.template @@ -0,0 +1,7 @@ +COGNITO_CLIENT_ID='' +COGNITO_CLIENT_SECRET='' +COGNITO_REDIRECT_URL='' +COGNITO_TOKEN_ENDPOINT='' +COGNITO_USER_POOL_ID='' +COGNITO_REGION='' +COGNITO_AUTH_URL='' diff --git a/.github/workflows/image_build_push.yml b/.github/workflows/image_build_push.yml new file mode 100644 index 0000000..2b780f8 --- /dev/null +++ b/.github/workflows/image_build_push.yml @@ -0,0 +1,98 @@ +name: docker-image-push-admin + +on: + push: + branches: [ master ] + + workflow_dispatch: + inputs: + docker_image_tag: + description: "Latest Docker image tags passed from e-mission-server repository on image build and push" + required: true + +env: + DOCKER_USER: ${{secrets.DOCKER_USER}} + DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}} + +jobs: + build: + runs-on: ubuntu-latest + + env: + DOCKER_TAG_FROM_WORKFLOW_DISPATCH: ${{ github.event.inputs.docker_image_tag }} + + steps: + - uses: actions/checkout@v4 + + - name: Set docker image tag from .env file + run: | + set -a; source .env; set +a + echo "DOCKER_TAG_FROM_PUSH=${SERVER_IMAGE_TAG}" >> $GITHUB_ENV + + - name: Print input docker image tag + run: | + echo "Event name: ${{ github.event_name }}" + echo "Latest docker image tag (push): ${{ env.DOCKER_TAG_FROM_PUSH }}" + echo "Latest docker image tag (workflow_dispatch): ${{ env.DOCKER_TAG_FROM_WORKFLOW_DISPATCH }}" + + - name: docker login + run: | # log into docker hub account + docker login -u $DOCKER_USER -p $DOCKER_PASSWORD + + - name: Get current date # get the date of the build + id: date + run: echo "::set-output name=date::$(date +'%Y-%m-%d--%M-%S')" + + - name: Run a one-line script + run: echo running in repo ${GITHUB_REPOSITORY#*/} branch ${GITHUB_REF##*/} on ${{ steps.date.outputs.date }} + + - name: build docker image + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + SERVER_IMAGE_TAG=$DOCKER_TAG_FROM_WORKFLOW_DISPATCH docker compose -f docker-compose-prod.yml build + else + SERVER_IMAGE_TAG=$DOCKER_TAG_FROM_PUSH docker compose -f docker-compose-prod.yml build + fi + docker images + + - name: rename docker image + run: | + docker image tag e-mission/opdash:0.0.1 $DOCKER_USER/${GITHUB_REPOSITORY#*/}:${GITHUB_REF##*/}_${{ steps.date.outputs.date }} + + - name: push docker image + run: | + docker push $DOCKER_USER/${GITHUB_REPOSITORY#*/}:${GITHUB_REF##*/}_${{ steps.date.outputs.date }} + + - name: Update .env file + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "Workflow_dispatch: New server image built and pushed, Updating image tag in .env" + echo "SERVER_IMAGE_TAG=$DOCKER_TAG_FROM_WORKFLOW_DISPATCH" > .env + else + echo "Push event: Restoring latest server image tag from .env" + fi + + - name: Add, Commit, Push changes to .env file + run: | + git config --local user.email "action@github.com" + git config --local user.name "Github Actions bot to update .env with latest tags" + if git diff --quiet; then + echo "Latest timestamp already present in .env file, no changes to commit" + else + git add .env + git commit -m "Updated docker image tag in .env file to the latest timestamp" + git push origin + fi + + - name: Create artifact text file + run: | + echo ${{ steps.date.outputs.date }} > admin_dash_tag_file.txt + echo "Created tag text file" + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: admin-dash-image-tag + path: admin_dash_tag_file.txt + overwrite: true + diff --git a/app_sidebar_collapsible.py b/app_sidebar_collapsible.py index 9bd342a..da74ade 100644 --- a/app_sidebar_collapsible.py +++ b/app_sidebar_collapsible.py @@ -17,6 +17,7 @@ from dash import Input, Output, dcc, html, Dash import dash_auth import logging +import base64 # Set the logging right at the top to make sure that debug # logs are displayed in dev mode # until https://github.com/plotly/dash/issues/532 is fixed @@ -29,15 +30,17 @@ import flask_talisman as flt - -OPENPATH_LOGO = "https://www.nrel.gov/transportation/assets/images/openpath-logo.jpg" +OPENPATH_LOGO = os.path.join(os.getcwd(), "assets/openpath-logo.jpg") +encoded_image = base64.b64encode(open(OPENPATH_LOGO, 'rb').read()).decode("utf-8") auth_type = os.getenv('AUTH_TYPE') if auth_type == 'cognito': from utils.cognito_utils import authenticate_user, get_cognito_login_page elif auth_type == 'basic': - from config import VALID_USERNAME_PASSWORD_PAIRS + VALID_USERNAME_PASSWORD_PAIRS = { + 'hello': 'world' + } app = Dash( external_stylesheets=[dbc.themes.BOOTSTRAP, dbc.icons.FONT_AWESOME], @@ -59,7 +62,8 @@ [ # width: 3rem ensures the logo is the exact width of the # collapsed sidebar (accounting for padding) - html.Img(src=OPENPATH_LOGO, style={"width": "3rem"}), + # html.Img(src=OPENPATH_LOGO, style={"width": "3rem"}), + html.Img(src=f"data:image/png;base64,{encoded_image}", style={"width": "3rem"}), # Working html.H2("OpenPATH"), ], className="sidebar-header", diff --git a/assets/openpath-logo.jpg b/assets/openpath-logo.jpg new file mode 100644 index 0000000..1e13c57 Binary files /dev/null and b/assets/openpath-logo.jpg differ diff --git a/config-fake.py b/config-fake.py deleted file mode 100644 index bcfc85f..0000000 --- a/config-fake.py +++ /dev/null @@ -1,21 +0,0 @@ -# This is a template for the "config.py" file. Put all of your valid data in this file and then change the name of this -# file to "config.py". -import os - -# Fill these variables when using AWS Cognito authentication; otherwise, keep them empty. -# All the variables of this class must be filled in using your credential data from your AWS Cognito panel. -class CognitoConfig: - CLIENT_ID = os.getenv("COGNITO_CLIENT_ID", '') - CLIENT_SECRET = os.getenv("COGNITO_CLIENT_SECRET", '') - REDIRECT_URL = os.getenv("COGNITO_REDIRECT_URL", '') - TOKEN_ENDPOINT = os.getenv("COGNITO_TOKEN_ENDPOINT", '') - USER_POOL_ID = os.getenv("COGNITO_USER_POOL_ID", '') - REGION = os.getenv("COGNITO_REGION", '') - AUTH_URL = os.getenv("COGNITO_AUTH_URL", '') - - -# Fill this variable when using basic authentication; otherwise, keep it empty. -# This dictionary contains all the valid usernames and passwords that users can authenticate with. -VALID_USERNAME_PASSWORD_PAIRS = { - 'hello': 'world' -} diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 75f8df2..df44e28 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -5,6 +5,8 @@ services: build: context: . dockerfile: docker/Dockerfile + args: + SERVER_IMAGE_TAG: ${SERVER_IMAGE_TAG} image: e-mission/opdash:0.0.1 ports: - "8050:8050" diff --git a/docker-compose-prod-nginx.yml b/docker-compose-prod-nginx.yml index d4d6abf..55fbde6 100644 --- a/docker-compose-prod-nginx.yml +++ b/docker-compose-prod-nginx.yml @@ -6,6 +6,8 @@ services: build: context: . dockerfile: docker/Dockerfile + args: + SERVER_IMAGE_TAG: ${SERVER_IMAGE_TAG} image: e-mission/opdash:0.0.1 environment: DASH_DEBUG_MODE: "True" diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml index 8b50892..eb284fd 100644 --- a/docker-compose-prod.yml +++ b/docker-compose-prod.yml @@ -5,6 +5,8 @@ services: build: context: . dockerfile: docker/Dockerfile + args: + SERVER_IMAGE_TAG: ${SERVER_IMAGE_TAG} image: e-mission/opdash:0.0.1 ports: - "8050:8050" diff --git a/docker/Dockerfile b/docker/Dockerfile index 188b1ac..8224c25 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,8 @@ -FROM shankari/e-mission-server:master_2024-07-19--34-43 +ARG SERVER_IMAGE_TAG + +FROM shankari/e-mission-server:master_${SERVER_IMAGE_TAG} + +ADD https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem /etc/ssl/certs/ ENV DASH_DEBUG_MODE True ENV SERVER_PORT 8050 @@ -17,10 +21,10 @@ COPY ./pages ./ WORKDIR /usr/src/app/utils COPY ./utils ./ WORKDIR /usr/src/app -COPY app.py config.py app_sidebar_collapsible.py assets globals.py globalsUpdater.py Procfile ./ +COPY app.py app_sidebar_collapsible.py globals.py globalsUpdater.py Procfile ./ WORKDIR /usr/src/app/assets -COPY assets/style.css ./ +COPY assets/ ./ RUN mkdir qrcodes # copy over test data diff --git a/docker/start.sh b/docker/start.sh index 05b2f12..8500a69 100755 --- a/docker/start.sh +++ b/docker/start.sh @@ -2,13 +2,7 @@ source setup/activate.sh # change the db host -echo "DB host = "${DB_HOST} -if [ -z ${DB_HOST} ] ; then - local_host=`hostname -i` - sed "s_localhost_${local_host}_" conf/storage/db.conf.sample > conf/storage/db.conf -else - sed "s_localhost_${DB_HOST}_" conf/storage/db.conf.sample > conf/storage/db.conf -fi +echo ${DB_HOST} # run the app # python app.py diff --git a/utils/cognito_utils.py b/utils/cognito_utils.py index 59203d4..17f2e30 100644 --- a/utils/cognito_utils.py +++ b/utils/cognito_utils.py @@ -4,16 +4,16 @@ import flask import requests import dash +import os -from config import CognitoConfig from utils import decode_jwt def get_tokens(code): - client_id = CognitoConfig.CLIENT_ID - client_secret = CognitoConfig.CLIENT_SECRET - redirect_uri = CognitoConfig.REDIRECT_URL - token_endpoint = CognitoConfig.TOKEN_ENDPOINT + client_id = os.getenv("COGNITO_CLIENT_ID", '') + client_secret = os.getenv("COGNITO_CLIENT_SECRET", '') + redirect_uri = os.getenv("COGNITO_REDIRECT_URL", '') + token_endpoint = os.getenv("COGNITO_TOKEN_ENDPOINT", '') encoded_data = base64.b64encode(f'{client_id}:{client_secret}'.encode('ascii')).decode('ascii') headers = { @@ -59,7 +59,7 @@ def get_cognito_login_page(text='Welcome to the dashboard', color='black'): dash.html.Label(text, style={ 'font-size': '15px', 'display': 'block', 'verticalAlign': 'top', 'padding': '15px', 'color': color }), - dbc.Button('Login with AWS Cognito', id='login-button', href=CognitoConfig.AUTH_URL, style={ + dbc.Button('Login with AWS Cognito', id='login-button', href=os.getenv("COGNITO_AUTH_URL", ''), style={ 'font-size': '14px', 'display': 'block', 'padding': '15px', 'verticalAlign': 'top', 'background-color': 'green', 'color': 'white' }), diff --git a/utils/decode_jwt.py b/utils/decode_jwt.py index 8f565bb..dca5c02 100644 --- a/utils/decode_jwt.py +++ b/utils/decode_jwt.py @@ -14,15 +14,14 @@ import urllib.request from jose import jwk, jwt from jose.utils import base64url_decode +import os -from config import CognitoConfig - -client_id = CognitoConfig.CLIENT_ID -client_secret = CognitoConfig.CLIENT_SECRET -redirect_uri = CognitoConfig.REDIRECT_URL -token_endpoint = CognitoConfig.TOKEN_ENDPOINT -user_pool_id = CognitoConfig.USER_POOL_ID -region = CognitoConfig.REGION +client_id = os.getenv("COGNITO_CLIENT_ID", '') +client_secret = os.getenv("COGNITO_CLIENT_SECRET", '') +redirect_uri = os.getenv("COGNITO_REDIRECT_URL", '') +token_endpoint = os.getenv("COGNITO_TOKEN_ENDPOINT", '') +user_pool_id = os.getenv("COGNITO_USER_POOL_ID", '') +region = os.getenv("COGNITO_REGION", '') keys_url = f'https://cognito-idp.{region}.amazonaws.com/{user_pool_id}/.well-known/jwks.json' # instead of re-downloading the public keys every time