Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 00b0811

Browse files
authored
SSO Migration & Container Deployment (#62)
* Dockerfile * Refactor: Black formatter Also include mypy into requirements.txt file * Remove support for configuration files & Update packages All the required configuration is now being set as environment variables Also, packages used are updated * Include OIDC authentication Include AuthenticationMiddleware via core_lib * Configure callback to authenticate using an access token This configures two modules: `remote_apparatus.py` for requesting an access token via client credentials grant and `controller.py` to give the required credentials via environment variables when the job is submitted * Enable OpenShift container account to create folders into relmons/ for job submission * Set environment variables into HTCondor config file Reference: https://htcondor.readthedocs.io/en/latest/man-pages/condor_submit.html * Bugfix: RelMon validation status Fix a logic error on /api/update endpoint that impedes the batch job running into HTCondor to update the RelMon status * Bugfix: Include some extra logging instruction to debug behaviour into HTCondor * Bugfix: Use the updated version of remote_apparatus.py into HTCondor Also, update how environment variables are sent to HTCondor into JDS configuration file * Bugfix: Double quote for wrapping environment variables * Bugfix: Repository version Clone directly the specific desired branch * Bugfix: Repair finished Remove access token from log file * Update Pylint workflow Use Ubuntu 22.04 for the runner and update Python version to 3.11.4 * Update Pylint Some features the old Pylint version used where removed in Python 3.11 For more details, please see: python/cpython#28618 * Modify Pylint score * Pylint: Avoid to scan core_lib and venv packages * Pylint & GitHub Actions 1. Update Pylint configuration (.pylintrc) 2. Raise the acceptance score to 9.75 3. Fix some linting issues: Encoding errors, broad exceptions, etc. 4. Increase the GitHub Action checkout version to 4 5. Disable linting for core_lib and venv packages * core_lib & Repository version for remote execution 1. Update core_lib to use the version available in PdmVWebCore/master 2. Update `local/file_creator.py` to pull the remote code from `master` instead of `SSOMigrationV2`
1 parent 5e8b89b commit 00b0811

20 files changed

Lines changed: 1439 additions & 1102 deletions

.dockerignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Ignore the following files for image building
2+
.github/
3+
logs/
4+
venv/
5+
frontend/node_modules/
6+
frontend/dist/
7+
8+
# Append the config file via secret files
9+
# or environment files
10+
config.cfg
11+
12+
# Ignore Python cache
13+
__pycache__/
14+
15+
# Ignore Docker Compose files
16+
relmonservice.yaml
17+
18+
relmonsvc.sh
19+
*.pid

.github/workflows/pylint.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,25 @@ on:
88

99
jobs:
1010
build:
11-
12-
runs-on: ubuntu-20.04
11+
runs-on: ubuntu-22.04
1312
name: Get newest code and run pylint
1413
steps:
1514
- name: Checkout repository
16-
uses: actions/checkout@v2
15+
uses: actions/checkout@v4
1716
with:
1817
submodules: true
19-
- name: Set up Python 3.6.8
18+
- name: Set up Python
2019
uses: actions/setup-python@v4
2120
with:
22-
python-version: "3.6.8"
21+
python-version: "3.11.4"
2322
- name: Install dependencies
2423
run: |
2524
python3 -m pip install --upgrade pip
2625
python3 -m pip install -r requirements.txt
2726
- name: Run pylint
28-
# --fail-under=9.5 - fail if score is below 9.5
27+
# --fail-under=9.75 - fail if score is below 9.75
2928
# --fail-on=E - fail if there were errors, regardless of the score
3029
# --reports=y - print a report at the end
3130
run: |
3231
python3 -m pylint --version
33-
python3 -m pylint --fail-under=9.5 --fail-on=E --reports=y `find . -type f | grep .py$ | xargs`
32+
python3 -m pylint --fail-under=9.75 --fail-on=E --reports=y `find . -type d \( -path ./venv -o -path ./core_lib \) -prune -o -type f | grep .py$ | xargs`

.gitmodules

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[submodule "core_lib"]
2+
path = core_lib
3+
url = https://github.com/cms-PdmV/PdmVWebCore.git
4+
branch = SSOMigration

.pylintrc

Lines changed: 3 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -60,88 +60,9 @@ confidence=
6060
# --enable=similarities". If you want to run only the classes checker, but have
6161
# no Warning level messages displayed, use "--disable=all --enable=classes
6262
# --disable=W".
63-
disable=print-statement,
64-
parameter-unpacking,
65-
unpacking-in-except,
66-
old-raise-syntax,
67-
backtick,
68-
long-suffix,
69-
old-ne-operator,
70-
old-octal-literal,
71-
import-star-module-level,
72-
non-ascii-bytes-literal,
73-
raw-checker-failed,
74-
bad-inline-option,
75-
locally-disabled,
76-
file-ignored,
77-
suppressed-message,
78-
useless-suppression,
79-
deprecated-pragma,
80-
use-symbolic-message-instead,
81-
apply-builtin,
82-
basestring-builtin,
83-
buffer-builtin,
84-
cmp-builtin,
85-
coerce-builtin,
86-
execfile-builtin,
87-
file-builtin,
88-
long-builtin,
89-
raw_input-builtin,
90-
reduce-builtin,
91-
standarderror-builtin,
92-
unicode-builtin,
93-
xrange-builtin,
94-
coerce-method,
95-
delslice-method,
96-
getslice-method,
97-
setslice-method,
98-
no-absolute-import,
99-
old-division,
100-
dict-iter-method,
101-
dict-view-method,
102-
next-method-called,
103-
metaclass-assignment,
104-
indexing-exception,
105-
raising-string,
106-
reload-builtin,
107-
oct-method,
108-
hex-method,
109-
nonzero-method,
110-
cmp-method,
111-
input-builtin,
112-
round-builtin,
113-
intern-builtin,
114-
unichr-builtin,
115-
map-builtin-not-iterating,
116-
zip-builtin-not-iterating,
117-
range-builtin-not-iterating,
118-
filter-builtin-not-iterating,
119-
using-cmp-argument,
120-
eq-without-hash,
121-
div-method,
122-
idiv-method,
123-
rdiv-method,
124-
exception-message-attribute,
125-
invalid-str-codec,
126-
sys-max-int,
127-
bad-python3-import,
128-
deprecated-string-function,
129-
deprecated-str-translate-call,
130-
deprecated-itertools-function,
131-
deprecated-types-field,
132-
next-method-defined,
133-
dict-items-not-iterating,
134-
dict-keys-not-iterating,
135-
dict-values-not-iterating,
136-
deprecated-operator-function,
137-
deprecated-urllib-function,
138-
xreadlines-attribute,
139-
deprecated-sys-function,
140-
exception-escape,
141-
comprehension-escape,
142-
raise-missing-from,
143-
consider-using-with,
144-
unspecified-encoding
63+
disable=consider-using-f-string,
64+
broad-exception-caught,
65+
consider-using-with
14566

14667
# Enable the message, report, category or checker with the given id(s). You can
14768
# either give multiple identifier separated by comma (,) or put this option
@@ -317,13 +238,6 @@ max-line-length=100
317238
# Maximum number of lines in a module.
318239
max-module-lines=1000
319240

320-
# List of optional constructs for which whitespace checking is disabled. `dict-
321-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
322-
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
323-
# `empty-line` allows space-only lines.
324-
no-space-check=trailing-comma,
325-
dict-separator
326-
327241
# Allow the body of a class to be on the same line as the declaration if body
328242
# contains single statement.
329243
single-line-class-stmt=no
@@ -564,9 +478,3 @@ known-standard-library=
564478
# Force import order to recognize a module as part of a third party library.
565479
known-third-party=enchant
566480

567-
568-
[EXCEPTIONS]
569-
570-
# Exceptions that will emit a warning when being caught. Defaults to
571-
# "BaseException, Exception".
572-
overgeneral-exceptions=BaseException,

Dockerfile

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Build web application bundle
2+
FROM node:16-buster-slim@sha256:1417528032837e47462ea8cfe983108b0152f989e95cba2ddfbe0f0ddc2dcfbd AS frontend
3+
4+
WORKDIR /usr/app
5+
6+
COPY frontend .
7+
8+
RUN npm install
9+
RUN npm run build
10+
11+
# Build dependencies
12+
FROM python:3.11.3-alpine3.18@sha256:caafba876f841774905f73df0fcaf7fe3f55aaf9cb48a9e369a41077f860d4a7 AS build
13+
14+
WORKDIR /usr/app
15+
RUN python -m venv /usr/app/venv
16+
ENV PATH="/usr/app/venv/bin:$PATH"
17+
18+
COPY requirements.txt .
19+
RUN pip install -r requirements.txt
20+
21+
# Create image for deployment
22+
FROM python:3.11.3-alpine3.18@sha256:caafba876f841774905f73df0fcaf7fe3f55aaf9cb48a9e369a41077f860d4a7 AS backend
23+
24+
RUN addgroup -g 1001 pdmv && adduser --disabled-password -u 1001 -G pdmv pdmv
25+
26+
RUN mkdir /usr/app && chown pdmv:pdmv /usr/app
27+
WORKDIR /usr/app
28+
29+
COPY --chown=pdmv:pdmv . .
30+
RUN rm -rf frontend/*
31+
32+
COPY --chown=pdmv:pdmv --from=frontend /usr/app/dist ./frontend/dist
33+
COPY --chown=pdmv:pdmv --from=build /usr/app/venv ./venv
34+
35+
RUN chmod -R 707 /usr/app/relmons/
36+
37+
USER 1001
38+
39+
ENV PATH="/usr/app/venv/bin:$PATH"
40+
CMD [ "python", "main.py" ]

config.cfg

Lines changed: 0 additions & 22 deletions
This file was deleted.

core_lib

Submodule core_lib added at 2bd7886

environment.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""
2+
This module parses some configuration variables from
3+
the runtime environment to use them in different sections
4+
from this application
5+
6+
Attributes:
7+
CALLBACK_URL (str): This is the url for the endpoint that HTCondor
8+
jobs use to update the status for the running RelMon job.
9+
For example: "https://cms-pdmv.cern.ch/relmonservice/api/update"
10+
For more details, please see the endpoint definition: /api/update.
11+
SERVICE_URL (str): This is the url for RelMonService2 application.
12+
For example: "https://cms-pdmv.cern.ch/relmonservice"
13+
It is used to include the application's url into email notifications
14+
and for request cookies/tokens for authenticating callback request.
15+
REPORTS_URL (str): This is the url for RelMon report page.
16+
For example: "https://cms-pdmv.cern.ch/relmon"
17+
This is a static web page that renders all outputs for the reports.
18+
SUBMISSION_HOST (str): This is the server where this application will open an SSH session
19+
to submit jobs through HTCondor. For example: "lxplus.cern.ch"
20+
REMOTE_DIRECTORY (str): This is the folder (into AFS or EOS) that stores
21+
all the required bundle files to submit a HTCondor job.
22+
SERVICE_ACCOUNT_USERNAME (str): Username to authenticate to `SUBMISSION_HOST`
23+
SERVICE_ACCOUNT_PASSWORD (str): Password to authenticate to `SUBMISSION_HOST`
24+
EMAIL_AUTH_REQUIRED (bool): If this environment variable is provided,
25+
the email client will authenticate to the email server. By default it is false,
26+
because this anonymous server does not require to authenticate.
27+
WEB_LOCATION_PATH (str): This is the path (AFS or EOS)
28+
where all RelMon reports are going to be stored. This is the path used by `REPORT_URL`
29+
application to load the reports static files.
30+
TICK_INTERNAL (int): Elapsed time in seconds to perform a tick, please see `controller.tick()`
31+
for more details.
32+
MONGO_DB_HOST (str): MongoDB host for opening a client session.
33+
MONGO_DB_PORT (int): MongoDB port for opening a client session.
34+
MONGO_DB_USER (str): MongoDB user to authenticate a new client session.
35+
MONGO_DB_PASSWORD (str): MongoDB password to authenticate a new client session.
36+
HOST (str): Flask listening hostname
37+
PORT (int): Flask port
38+
DEBUG (bool): Enables DEBUG mode for RelMonService2 application
39+
ENABLE_AUTH_MIDDLEWARE (bool): Enables the AuthenticationMiddleware to parse JWT
40+
or enable the application to handle OIDC flow by itself.
41+
SECRET_KEY (str): Flask secret key.
42+
CLIENT_ID (str): Client ID related to RelMonService2 application
43+
or the reverse proxy that provides authentication.
44+
CALLBACK_CLIENT_ID (str): Client ID for CLI integration application.
45+
CALLBACK_CLIENT_SECRET (str): Client secret for CLI integration application.
46+
"""
47+
import os
48+
import inspect
49+
50+
# RelMonService2 application
51+
CALLBACK_URL: str = os.getenv("CALLBACK_URL", "")
52+
SERVICE_URL: str = os.getenv("SERVICE_URL", "")
53+
REPORTS_URL: str = os.getenv("REPORTS_URL", "")
54+
SUBMISSION_HOST: str = os.getenv("SUBMISSION_HOST", "")
55+
REMOTE_DIRECTORY: str = os.getenv("REMOTE_DIRECTORY", "")
56+
SERVICE_ACCOUNT_USERNAME: str = os.getenv("SERVICE_ACCOUNT_USERNAME", "")
57+
SERVICE_ACCOUNT_PASSWORD: str = os.getenv("SERVICE_ACCOUNT_PASSWORD", "")
58+
EMAIL_AUTH_REQUIRED: bool = bool(os.getenv("EMAIL_AUTH_REQUIRED"))
59+
WEB_LOCATION_PATH: str = os.getenv("WEB_LOCATION_PATH", "")
60+
TICK_INTERVAL: int = int(os.getenv("TICK_INTERVAL", "600"))
61+
62+
# MongoDB database
63+
MONGO_DB_HOST: str = os.getenv("MONGO_DB_HOST", "")
64+
MONGO_DB_PORT: int = int(os.getenv("MONGO_DB_PORT", "27017"))
65+
MONGO_DB_USER: str = os.getenv("MONGO_DB_USER", "")
66+
MONGO_DB_PASSWORD: str = os.getenv("MONGO_DB_PASSWORD", "")
67+
68+
# Flask web server
69+
HOST: str = os.getenv("HOST", "0.0.0.0")
70+
PORT: int = int(os.getenv("PORT", "8000"))
71+
DEBUG: bool = bool(os.getenv("DEBUG"))
72+
ENABLE_AUTH_MIDDLEWARE: bool = bool(os.getenv("ENABLE_AUTH_MIDDLEWARE"))
73+
74+
# OAuth2 credentials
75+
SECRET_KEY: str = os.getenv("SECRET_KEY", "")
76+
CLIENT_ID: str = os.getenv("CLIENT_ID", "")
77+
CALLBACK_CLIENT_ID: str = os.getenv("CALLBACK_CLIENT_ID", "")
78+
CALLBACK_CLIENT_SECRET: str = os.getenv("CALLBACK_CLIENT_SECRET", "")
79+
80+
# Check that all environment variables are provided
81+
missing_environment_variables: dict[str, str] = {
82+
k: v
83+
for k, v in globals().items()
84+
if not k.startswith("__")
85+
and not inspect.ismodule(v)
86+
and not isinstance(v, bool)
87+
and not v
88+
}
89+
90+
if missing_environment_variables:
91+
msg: str = (
92+
"There are some environment variables "
93+
"required to be set before running this application\n"
94+
"Please set the following values via environment variables\n"
95+
"For more details, please see the description available into `environment.py` module\n"
96+
f"{list(missing_environment_variables.keys())}"
97+
)
98+
raise RuntimeError(msg)

0 commit comments

Comments
 (0)