Skip to content
Snippets Groups Projects
Unverified Commit 0aade867 authored by Marco Emilio "sphakka" Poleggi's avatar Marco Emilio "sphakka" Poleggi
Browse files

Moved Docker files in the right places. README completed. Makefile with all...

Moved Docker files in the right places. README completed. Makefile with all docker commands. Application small fixes

Signed-off-by: default avatarMarco Emilio "sphakka" Poleggi <marcoep@ieee.org>
parent 777327a8
No related branches found
No related tags found
No related merge requests found
# Use Python 3.11 slim image as base # Base image
FROM python:3.11-slim FROM python:3.12-alpine
# Set working directory # Set working directory
WORKDIR /app WORKDIR /app
# Set environment variables # Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \ ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \ FLASK_APP=main.py \
FLASK_APP=backend/main.py \
FLASK_ENV=development FLASK_ENV=development
# Install system dependencies
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
gcc \
python3-dev \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements first to leverage Docker cache # Copy requirements first to leverage Docker cache
COPY requirements.txt . COPY requirements.txt .
...@@ -26,12 +18,12 @@ RUN pip install --no-cache-dir -r requirements.txt ...@@ -26,12 +18,12 @@ RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application # Copy the rest of the application
COPY . . COPY . .
# Create a non-root user and switch to it # Create a non-root user
RUN useradd -m appuser && chown -R appuser:appuser /app RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser USER appuser
# Expose the port the app runs on # Expose the port the app runs on
EXPOSE 8000 EXPOSE 8000
# Command to run the application # Command to run the application
CMD ["python3", "backend/main.py"] CMD ["python", "main.py"]
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
from flask import Flask, request, jsonify from flask import Flask, request, jsonify
from flask_cors import CORS from flask_cors import CORS
import boto3 import boto3
import json # import json
import logging import logging
from functools import wraps from functools import wraps
from dotenv import load_dotenv from dotenv import load_dotenv
...@@ -33,8 +33,9 @@ def handle_aws_errors(f): ...@@ -33,8 +33,9 @@ def handle_aws_errors(f):
app = Flask(__name__) app = Flask(__name__)
CORS(app) CORS(app)
# Initialize S3 client TODO: Add your S3 credentials as ENV variables or in # Initialize S3 client
# file '~/.aws/credentials' # TODO: Add your S3 credentials as ENV variables or in file
# '~/.aws/credentials'
s3_client = boto3.client( s3_client = boto3.client(
's3', 's3',
aws_access_key_id=os.getenv('SWITCH_ACCESS_KEY_ID'), aws_access_key_id=os.getenv('SWITCH_ACCESS_KEY_ID'),
...@@ -116,7 +117,8 @@ def logout(): ...@@ -116,7 +117,8 @@ def logout():
def unenroll(): def unenroll():
""" """
Endpoint to handle user unenrollment Endpoint to handle user unenrollment
Expected JSON payload: {'email': 'user@example.com', 'password': 'userpassword'} Expected JSON payload: {'email': 'user@example.com'}
or (bonus): {'email': 'user@example.com', 'password': 'userpassword'}
""" """
pass pass
...@@ -125,6 +127,6 @@ if __name__ == '__main__': ...@@ -125,6 +127,6 @@ if __name__ == '__main__':
logger.info("Starting Flask application...") logger.info("Starting Flask application...")
# Create the bucket if it doesn't exist # Create the bucket if it doesn't exist
s3_client.create_bucket(Bucket=BUCKET_NAME) s3_client.create_bucket(Bucket=BUCKET_NAME)
app.run(host='0.0.0.0', port=8000) app.run(host='0.0.0.0', port=8000, debug=True)
except Exception as e: except Exception as e:
logger.critical(f"Failed to start application: {str(e)}") logger.critical(f"Failed to start application: {str(e)}")
# Use Python 3.9 slim image as base # Base image
FROM python:3.9-slim FROM python:3.12-alpine
# Set working directory in container # Set working directory in container
WORKDIR /app WORKDIR /app
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
FLASK_APP=main.py \
FLASK_ENV=development
# Copy requirements first to leverage Docker cache # Copy requirements first to leverage Docker cache
COPY requirements.txt . COPY requirements.txt .
...@@ -13,9 +18,9 @@ RUN pip install --no-cache-dir -r requirements.txt ...@@ -13,9 +18,9 @@ RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application # Copy the rest of the application
COPY . . COPY . .
# Create a non-root user for security # Create a non-root user
RUN useradd -m myuser RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER myuser USER appuser
# Expose the port the app runs on # Expose the port the app runs on
EXPOSE 3000 EXPOSE 3000
......
...@@ -46,10 +46,12 @@ ...@@ -46,10 +46,12 @@
<h1 class="welcome-text">Welcome to Dashboard</h1> <h1 class="welcome-text">Welcome to Dashboard</h1>
<p>You are successfully logged in!</p> <p>You are successfully logged in!</p>
<button onclick="logout()" class="button">Logout</button> <button onclick="logout()" class="button">Logout</button>
<button onclick="unenroll()" class="button">Remove account</button>
</div> </div>
<script> <script>
// Get email from URL or localStorage (you should implement proper state management) /* Get email from URL or localStorage (you should implement proper state
management) */
const email = localStorage.getItem('userEmail'); const email = localStorage.getItem('userEmail');
console.log(email); console.log(email);
async function logout() { async function logout() {
...@@ -70,7 +72,28 @@ ...@@ -70,7 +72,28 @@
alert('Logout failed: ' + data.status); alert('Logout failed: ' + data.status);
} }
} catch (error) { } catch (error) {
alert('Error during logout'); alert('Error during logout. ' + error);
}
}
async function unenroll() {
try {
const response = await fetch('http://localhost:8000/unenroll', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ "email": email }),
});
const data = await response.json();
if (data.status === 'OK') {
localStorage.removeItem('userEmail');
window.location.href = 'index.html';
} else {
alert('Unenroll failed: ' + data.status);
}
} catch (error) {
alert('Error during unenroll. ' + error);
} }
} }
</script> </script>
......
...@@ -47,4 +47,3 @@ ...@@ -47,4 +47,3 @@
</div> </div>
</body> </body>
</html> </html>
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
alert('Login failed: ' + data.status); alert('Login failed: ' + data.status);
} }
} catch (error) { } catch (error) {
alert('Error during login'); alert('Error during login. ' + error);
} }
}); });
</script> </script>
......
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
alert('Sign up failed: ' + data.status); alert('Sign up failed: ' + data.status);
} }
} catch (error) { } catch (error) {
alert('Error during sign up'); alert('Error during sign up. ' + error);
} }
}); });
</script> </script>
......
...@@ -22,6 +22,8 @@ switch_access_key_id=${SWITCH_ACCESS_KEY_ID:?'Please set ENV variable'} ...@@ -22,6 +22,8 @@ switch_access_key_id=${SWITCH_ACCESS_KEY_ID:?'Please set ENV variable'}
switch_secret_access_key=${SWITCH_SECRET_ACCESS_KEY:?'Please set ENV variable'} switch_secret_access_key=${SWITCH_SECRET_ACCESS_KEY:?'Please set ENV variable'}
s3_bucket_name=${S3_BUCKET_NAME:?'Please set ENV variable'} s3_bucket_name=${S3_BUCKET_NAME:?'Please set ENV variable'}
export SWITCH_ENDPOINT_URL SWITCH_ENDPOINT_URL SWITCH_ACCESS_KEY_ID SWITCH_SECRET_ACCESS_KEY S3_BUCKET_NAME
backend_pid= backend_pid=
backend_log="${web_sso_root}/backend/main.log" backend_log="${web_sso_root}/backend/main.log"
backend_main="${web_sso_root}/backend/main.py" backend_main="${web_sso_root}/backend/main.py"
......
Docker files here
...@@ -12,13 +12,22 @@ backend_port := 8000 ...@@ -12,13 +12,22 @@ backend_port := 8000
portal_url := "http://localhost:$(frontend_port)" portal_url := "http://localhost:$(frontend_port)"
terminal := xfce4-terminal terminal := xfce4-terminal
term_opts := term_opts :=
term_title := "Web SSO application"
app_components := frontend backend
docker_username := $(DOCKER_USERNAME)
docker_bcname := web-sso
define app_ports :=
frontend:$(frontend_port)
backend:$(backend_port)
endef
ifeq ($(terminal), xterm) ifeq ($(terminal), xterm)
term_opts += -T $(term_title) -hold term_opts += -hold
else else
# should catch most other emulators out there # should catch most other emulators out there
term_opts += -T $(term_title) -H term_opts += -H
endif endif
define _help_msg := define _help_msg :=
...@@ -26,16 +35,33 @@ Usage: ...@@ -26,16 +35,33 @@ Usage:
make [command] make [command]
Commands Basic commands
help ...guess what ^^ help ...guess what ^^
(v)install install the application locally (in a Python virtual env that will be created) (v)install install the application locally (in a Python virtual env that will be created)
(t)run (open a terminal and) run the application (t)run (open a terminal and) run the application
The following Docker commands acts on all application images/containers
dlogs stream app logs to separate terminal emulators
docker => docker-build + docker-push
docker-build build images
docker-push push images to Docker Hub -- needs env DOCKER_USERNAME
drestart restart app containers
drm remove (stopped) containers
drun launch app containers from images
dstart start app containers
dstatus list app containers
dstop stop app containers
Options Options
-s silent mode
docker_username set your Docker Hub user name. Default from env
DOCKER_USERNAME, currently '${DOCKER_USERNAME}'
sandbox_dir where to install the app (under '$(prefix)/'). Default: $(sandbox_dir) sandbox_dir where to install the app (under '$(prefix)/'). Default: $(sandbox_dir)
terminal the terminal emulator to be lunched with command 'trun'. Default: $(terminal). Supported: xterm, xfce4-terminal. terminal the terminal emulator to be lunched with command
'trun'. Default: $(terminal). Supported: xterm, xfce4-terminal.
Examples Examples
...@@ -55,6 +81,10 @@ Examples ...@@ -55,6 +81,10 @@ Examples
Run the application in terminal emulator 'xterm': Run the application in terminal emulator 'xterm':
make terminal=xterm trun make terminal=xterm trun
Build and push your app images to Docker Hub:
make docker
endef endef
define _s3_creds := define _s3_creds :=
...@@ -62,8 +92,6 @@ SWITCH_ENDPOINT_URL='<your-s3-endpoint>' ...@@ -62,8 +92,6 @@ SWITCH_ENDPOINT_URL='<your-s3-endpoint>'
SWITCH_ACCESS_KEY_ID='<your-s3-access-key-id>' SWITCH_ACCESS_KEY_ID='<your-s3-access-key-id>'
SWITCH_SECRET_ACCESS_KEY='<your-s3-secret-key>' SWITCH_SECRET_ACCESS_KEY='<your-s3-secret-key>'
S3_BUCKET_NAME='project-web-sso' S3_BUCKET_NAME='project-web-sso'
export SWITCH_ENDPOINT_URL SWITCH_ENDPOINT_URL SWITCH_ACCESS_KEY_ID SWITCH_SECRET_ACCESS_KEY S3_BUCKET_NAME
endef endef
define echoo define echoo
...@@ -74,7 +102,16 @@ define echoe ...@@ -74,7 +102,16 @@ define echoe
$(echoo) >&2 $(echoo) >&2
endef endef
.PHONY: help _sandbox _venv _s3cred install vinstall trun run define log-info
printf >&2 "[info] %b\n"
endef
define log-error
printf >&2 "[error] %b\n"
endef
.PHONY: _check_docker _check_term _danyop_by_cid _danyop_by_cname dlogs docker docker-build docker-push drestart drm drun dstart dstatus dstop help _install install run _s3cred _sandbox _term trun _venv vinstall
all: help all: help
...@@ -86,20 +123,22 @@ _venv: _sandbox ...@@ -86,20 +123,22 @@ _venv: _sandbox
_install: _sandbox _install: _sandbox
rsync -Cabhv -L --suffix=.bak $(app_sdir) $(sandbox_dir) || exit 1 rsync -Cabhv -L --suffix=.bak $(app_sdir) $(sandbox_dir) || exit 1
pip install $(pip_opts) $(application_dir)/frontend/requirements.txt || for comp in $(app_components); do
exit 1 $(log-info) "$${comp}: installing app component's dependencies..."
pip install $(pip_opts) $(application_dir)/backend/requirements.txt || pip -q install $(pip_opts) $(application_dir)/$${comp}/requirements.txt ||
exit 1 exit 1
done
$(MAKE) _s3cred $(MAKE) _s3cred
_s3cred: _s3cred:
[ -r $(s3_cred_file) ] && { [ -r $(s3_cred_file) ] && {
$(echoe) "[info] $(s3_cred_file): file exists. Won't touch it..." $(log-info) "$(s3_cred_file): file exists. Won't touch it..."
exit 0 exit 0
} }
$(echoo) "$(_s3_creds)" > $(s3_cred_file) || exit 1 $(echoo) "$(_s3_creds)" > $(s3_cred_file) || exit 1
chmod 0600 $(s3_cred_file) chmod 0600 $(s3_cred_file)
$(echoe) "[info] Please adapt your AWS/S3 credentials in file '$(s3_cred_file)'" ln -s $(application_dir)/backend/.env $(s3_cred_file)
$(log-info) "Please adapt your AWS/S3 credentials in file '$(s3_cred_file)'"
install: install:
$(MAKE) pip_opts='$(pip_opts) --user' _install || exit 1 $(MAKE) pip_opts='$(pip_opts) --user' _install || exit 1
...@@ -107,23 +146,111 @@ install: ...@@ -107,23 +146,111 @@ install:
vinstall: _venv vinstall: _venv
source $(sandbox_dir)/bin/activate source $(sandbox_dir)/bin/activate
$(MAKE) _install $(MAKE) _install
$(echoe) "[ok] Application installed in '$(application_dir)'" $(log-info) "Application installed in '$(application_dir)'"
$(echoe) "[info] To activate your virtual env, please, open a terminal and run:\n\ $(log-info) "To activate your virtual env, please, open a terminal and run:\n\
cd $(sandbox_dir) && source bin/activate" cd $(sandbox_dir) && source bin/activate"
run: run:
export WEB_SSO_ROOT=$(application_dir) export WEB_SSO_ROOT=$(application_dir)
$(application_dir)/run.sh $(application_dir)/run.sh
trun:
_check_term:
which $(terminal) 2> /dev/null || { which $(terminal) 2> /dev/null || {
$(echoe) "[error] $(terminal): not found. Please set your terminal program and retry:\n\tmake terminal=YOUR_TERMINAL_PROGRAM run" $(log-error) "$(terminal): not found. Please set your terminal program and retry:\n\tmake terminal=YOUR_TERMINAL_EMULATOR trun"
exit 1 exit 1
} }
$(terminal) $(term_opts) \
-e "sh -c 'export WEB_SSO_ROOT=$(application_dir); \
$(application_dir)/run.sh'" &
_term:
$(terminal) $(term_opts) -T "$(term_title)" -e "$(in_term_command)" &
trun: _check_term
$(MAKE) term_title="Web SSO application" \
in_term_command="sh -c 'export WEB_SSO_ROOT=$(application_dir); \
$(application_dir)/run.sh'" _term
_check_docker:
docker ps -q || {
$(log-error) "Please install and start docker"
exit 1
}
[ "$(docker_username)" ] || {
$(log-error) "Please set: docker_username=DOCKER_USERNAME"
exit 1
}
docker-build: _check_docker
for comp in $(app_components); do
docker build --tag $(docker_username)/$(docker_bcname)-$${comp} \
$(application_dir)/$${comp}
done
docker-push: _check_docker
for comp in $(app_components); do
docker push $(docker_username)/$(docker_bcname)-$${comp}
done
docker:
$(MAKE) docker-build && $(MAKE) docker-push
# Use --name to avoid duplicates
drun:
ports="$(app_ports)"
for comp in $(app_components); do
port=$$(printf "%b" "$${ports}" | \
sed -rn "s/^$${comp}:([[:digit:]]+)$$/\\1/p")
docker run --detach --name=$(docker_bcname)-$${comp} \
--publish=$${port}:$${port} --env-file=$(s3_cred_file) \
$(docker_username)/$(docker_bcname)-$${comp}
done
# Docker generic operation $dop loop by container id
_danyop_by_cid:
[ "$(dop)" ] || {
$(log-error) "No docker operation specified"
exit 1
}
for comp in $(app_components); do
cid=$$(docker ps -aq \
--filter="name=$(docker_bcname)-$${comp}")
if [ "$${cid}" ]; then docker $(dop) $${cid}; fi
done
# Docker generic operation $dop loop by container name
_danyop_by_cname:
[ "$(dop)" ] || {
$(log-error) "No docker operation specified"
exit 1
}
for comp in $(app_components); do
docker $(dop) $(docker_bcname)-$${comp}
done
drm:
$(MAKE) dop=rm _danyop_by_cname
dstart:
$(MAKE) dop=start _danyop_by_cname
dstop:
$(MAKE) dop=stop _danyop_by_cname
dstatus:
docker ps -a --filter="name=$(docker_bcname)"
$(echoe) "IP ADDRESSES"
$(MAKE) dop="inspect --format='{{.NetworkSettings.IPAddress}} {{.Name}}'" \
_danyop_by_cname
dlogs: _check_term
for comp in $(app_components); do
$(MAKE) term_title="Web SSO application $${comp}" \
in_term_command="sh -c \
'docker container logs --follow $(docker_bcname)-$${comp}'" _term
done
drestart:
$(MAKE) dop=restart _danyop_by_cname
help: help:
@: $(info $(_help_msg)) @: $(info $(_help_msg))
...@@ -337,7 +337,7 @@ map: ...@@ -337,7 +337,7 @@ map:
└── conf <= Cloud-init files └── conf <= Cloud-init files
``` ```
You shall: :hammer_and_wrench: You shall:
1. Fork this repository. 1. Fork this repository.
2. Complete the Python back-end file `Application/backend/main.py`. See the 2. Complete the Python back-end file `Application/backend/main.py`. See the
...@@ -390,11 +390,11 @@ You will get bonus for any of the following improvements. ...@@ -390,11 +390,11 @@ You will get bonus for any of the following improvements.
To test your application before deploying it as a K8s service, you can install To test your application before deploying it as a K8s service, you can install
and run it locally in your workstation. and run it locally in your workstation.
:bulb: It is strongly recommended to install Python's "virtualenv": :hammer_and_wrench: **It is strongly recommended to install Python's "virtualenv":**
* [virtualenv](https://virtualenv.pypa.io/en/latest/index.html), and * [virtualenv](https://virtualenv.pypa.io/en/latest/index.html), and
* [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/). * [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/).
At the top-level of your repo clone, get an overview of administrative At the top-level of your Git repo clone, get an overview of administrative
commands and options: commands and options:
``` shell ``` shell
...@@ -407,28 +407,64 @@ Then, install the application in a virtual env (automatically created) ...@@ -407,28 +407,64 @@ Then, install the application in a virtual env (automatically created)
$ make vinstall $ make vinstall
``` ```
Otherwise, plain install (you might need to install python dependencies Otherwise, plain install -- you might need to install python dependencies
manually): *manually*:
``` shell ``` shell
$ make install $ make install
``` ```
Put your SwitchEngines EC2 credentials in file
`<sandbox>/Application/s3_credentials.env`, which should be already there.
Finally, run the application in the current console: Finally, run the application in the current console:
``` shell ``` shell
$ make run $ make run
``` ```
Or, run in another terminal: Or, run it in its own terminal:
``` shell ``` shell
$ make trun $ make trun
``` ```
#### Rebuild the Docker images #### Managing the containerized application with Docker
:hammer_and_wrench: **Install the following Docker packages on your workstation according
to your distribution's instructions: docker(.io), docker-cli,
(docker-)buildx**
:bulb: Please, peruse the `Makefile` to learn the real Docker commands.
After installation, switch back to your git clone directory, then run:
``` shell
$ make docker-build
```
Then, run the containers:
``` shell
$ make drun
```
Get useful information -- IP addresses, ports, etc.:
``` shell
$ make -s dstatus
```
Watch logs of running containers with:
``` shell
$ make -s dlogs
```
When ready for deployment on your VM (you'll be asked for your password/token):
``` shell
$ docker login
$ make -s docker-push
```
:construction: **need details** You can manage your containers with the other make commands: dstop, dstart,
drm, etc.
#### Test workflow #### Test workflow
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment