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

Actualizar main #450

Merged
merged 73 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
0db9154
chore: move non-secret production env variables to settings defaults
fagiannoni Oct 30, 2023
8440f51
chore: move non-secret production env variables to docker-compose.yml
fagiannoni Oct 30, 2023
de7cab0
fix: add .env.default to prioritize env variables
fagiannoni Oct 30, 2023
9a2d669
chore: move non-secret production frontend env variables to .env.default
fagiannoni Oct 30, 2023
94ab968
feat: final adjustment of dot envs
fagiannoni Dec 18, 2023
b5e7259
Merge branch 'dev' into prepare-deploy
fagiannoni Dec 22, 2023
1be547c
chore: final adjustments
fagiannoni Dec 22, 2023
b831cc9
chore: move non-secret default variables to .env.default frontend
fagiannoni Dec 22, 2023
8b380c3
chore: remove unused comment
fagiannoni Dec 22, 2023
218ec37
Merge branch 'dev' into prepare-deploy
kovaxis Dec 26, 2023
fa36be8
fix: add redis uri in development env file
kovaxis Dec 26, 2023
bfe2c29
fix: replace python_env for node_env in frontend
kovaxis Dec 26, 2023
12e56c6
docs: env file formatting and docs
kovaxis Dec 26, 2023
075c380
perf: profile plan generation
kovaxis Dec 30, 2023
455bea9
style: fix overlong comments
kovaxis Dec 31, 2023
a122332
Merge branch 'dev' into prepare-deploy
fagiannoni Dec 31, 2023
6a85d11
fix: attempt to fix default env file
fagiannoni Dec 31, 2023
c51938f
chore: remove unnecesary variable and improve docs
fagiannoni Dec 31, 2023
3992f1d
docs: improve env vars comments
fagiannoni Dec 31, 2023
4febac3
chore: remove unnecessary step in Dockerfile backend
fagiannoni Dec 31, 2023
5978e66
chore: add line at the end of Dockerfile backend
fagiannoni Dec 31, 2023
f200370
chore: remove redundancies in Dockerfiles
fagiannoni Dec 31, 2023
4cceab1
docs: improve env variables comments frontend
fagiannoni Dec 31, 2023
082e93f
fix: make vite use also the default env file
fagiannoni Dec 31, 2023
4ad6dc2
Merge branch 'dev' into optimize-dnf
kovaxis Dec 31, 2023
54435cb
fix: move frontend default env var required in the build process to t…
fagiannoni Dec 31, 2023
6c0abcf
fix: also use default env file in frontend
fagiannoni Dec 31, 2023
a0c2010
refactor: move function to utils
fagiannoni Dec 31, 2023
37d21cf
chore: missing import last commit
fagiannoni Dec 31, 2023
4a65185
fix: another attempt to fix env default file frontend
fagiannoni Dec 31, 2023
b74b755
fix: add missing frontend var
fagiannoni Dec 31, 2023
788648c
refactor: change default env file names to production
fagiannoni Dec 31, 2023
1763491
perf: optimize hidden requirement search
kovaxis Dec 31, 2023
adfa462
chore: remove useless env file from frontend because of lack of secrets
fagiannoni Dec 31, 2023
5711c98
feat: set a timelimit on the solver
kovaxis Dec 31, 2023
5032693
chore: remove dead test code
kovaxis Dec 31, 2023
48d991d
fix: outdated test
kovaxis Dec 31, 2023
6ce9143
chore: remove the database folder
fagiannoni Dec 31, 2023
0da6fa7
chore: minor refactor to docker compose yml
fagiannoni Dec 31, 2023
ba5d31e
fix: missing file name update
fagiannoni Dec 31, 2023
392028a
chore: minor fixes
fagiannoni Dec 31, 2023
b6df9c5
chore: implement deploy shell files and playbook
fagiannoni Jan 1, 2024
8c490c6
chore: minor adjustments to deploy shell file
fagiannoni Jan 1, 2024
b540c22
chore: finish new version of ansible playbook
fagiannoni Jan 2, 2024
2f183e1
chore: add docker logs env vars
fagiannoni Jan 2, 2024
e468ec7
fix: attempt to solve broken playbook
fagiannoni Jan 2, 2024
454dfe0
chore: more adjustment to playbook and update docs
fagiannoni Jan 2, 2024
15191fa
feat: cache student data with redis
kovaxis Jan 2, 2024
a942771
style: ruff requires weird import sorting
kovaxis Jan 2, 2024
fd18dc6
feat: add 40023 optativos de profundizacion
kovaxis Jan 2, 2024
69fae08
Merge branch 'dev' into prepare-deploy
fagiannoni Jan 5, 2024
21ac076
chore: run formatter
fagiannoni Jan 5, 2024
334dbbd
chore: format import position
fagiannoni Jan 5, 2024
a6c830a
chore: comment to avoid unnecessary linting warning
fagiannoni Jan 7, 2024
172edcb
chore: final adjustments to deploy files
fagiannoni Jan 7, 2024
64d51c9
chore: temporary change to test in prepare-deploy branch
fagiannoni Jan 7, 2024
02d3628
chore: minor change to test deploy
fagiannoni Jan 7, 2024
00e5e98
chore: finish definitely all deploy files
fagiannoni Jan 7, 2024
2fd2b93
docs: improve documentation of deploy process
fagiannoni Jan 7, 2024
277492c
Merge pull request #390 from open-source-uc/prepare-deploy
fagiannoni Jan 7, 2024
6257c98
feat: add contex menu related instructions
shantifabri Jan 22, 2024
e13374e
fix: change failed classes style
shantifabri Jan 22, 2024
94c3077
chore: update home gif
shantifabri Jan 22, 2024
64b31bd
Merge pull request #427 from open-source-uc/leyenda-update
Diegothx Apr 11, 2024
f544de7
Merge branch 'dev' into optimize-dnf
kovaxis Jun 18, 2024
6e20401
feat: update deps, fix linting, black -> ruff formatter
kovaxis Jun 18, 2024
9f4f952
arreglar redis
kovaxis Jun 18, 2024
08f5749
chore: fix redis
kovaxis Jun 18, 2024
5c89cc8
Merge pull request #413 from open-source-uc/optimize-dnf
kovaxis Jun 18, 2024
25bb287
Merge branch 'dev' into add-40023-prof-opts
kovaxis Jun 18, 2024
e75f044
Merge pull request #421 from open-source-uc/add-40023-prof-opts
kovaxis Jun 18, 2024
5592b49
fix: deploy update script
fagiannoni Jul 3, 2024
83fcf65
Merge pull request #451 from open-source-uc/fix/deploy-script
fagiannoni Jul 3, 2024
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
3 changes: 1 addition & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@
"charliermarsh.ruff",
"kokakiwi.vscode-just",
"redhat.ansible",
"github.vscode-github-actions",
"ms-python.black-formatter"
"github.vscode-github-actions"
],
"settings": {
"terminal.integrated.env.linux": {
Expand Down
14 changes: 5 additions & 9 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,12 @@ jobs:
poetry install
poetry run prisma generate

- name: Run black
uses: wearerequired/lint-action@v2
- name: Run ruff formatter
uses: chartboost/ruff-action@v1
with:
github_token: ${{ secrets.github_token }}
auto_fix: ${{ github.event_name == 'pull_request' }}
black: true
black_dir: backend
black_command_prefix: poetry run
black_auto_fix: true

args: "format --diff"
src: "./backend"

- name: Run ruff
uses: chartboost/ruff-action@v1
with:
Expand Down
1 change: 0 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"ms-vscode-remote.remote-containers",
"kokakiwi.vscode-just",
"ms-python.python",
"ms-python.black-formatter",
"charliermarsh.ruff",
"prisma.prisma",
"bradlc.vscode-tailwindcss",
Expand Down
6 changes: 2 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,12 @@
// Black + Ruff
"python.formatting.provider": "none",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
// Prevents ruff-vscode#128
"source.organizeImports.isort": true,
}
},
"ruff.args": [
"--config=/workspaces/planner/backend/pyproject.toml"
Expand Down
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ Sigue en la sección [Desarrollo general](#desarrollo-general).

Una vez listo, podrás entrar a la app en [http://localhost:3000](http://localhost:3000) 🎉


Necesitaras un nombre de usuario para acceder a CAS. Puedes acceder con `testuser` o con otros usuarios definidos en `cas-mock-users.json`.

Necesitaras un nombre de usuario para acceder a CAS. Puedes acceder con `testuser` o con otros usuarios definidos en `cas-mock-users.json`.

Para realizar acciones sobre el repositorio (migraciones, generación de código, etc) puedes usar:

- el task runner de VSCode (<kbd>Ctrl/Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> -> _"Tasks: Run Task"_).
- `just` en la linea de comandos. Para ver comandos disponibles, corre `just` desde cualquier carpeta.

Es importante que cuando:

- Cambias la estructura de la API, corras la tarea _"Generate client"_ (también disponible en modo watch).
- Cambies el esquema de la base de datos, corras la tarea _"Create/apply migrations"_ para que los cambios se reflejen en la base de datos.

Expand All @@ -89,6 +89,7 @@ El proyecto se integra con dos servicios externos: SIDING (para acceder a mallas
## Deployment

### Deployment automático

Para deployments a producción, se provee un playbook de [Ansible](https://docs.ansible.com/ansible/latest/index.html)
que permite levantar la app completa de principio a fin, pensado para su uso en un entorno de producción, en particular
en un servidor corriendo [Rocky Linux 9](https://rockylinux.org/).
Expand All @@ -102,12 +103,12 @@ $ ansible-playbook infra/playbook.yml -i <IP>, -u <USUARIO>
Asumiendo que ya se tenga una llave SSH al servidor. El playbook es completamente idempotente, por lo que
también puede ser utilizado para corregir configuration drift en un servidor de producción.

El playbook opcionalmente provee prompts para entregar credenciales de Tailscale, Netdata y SIDING. Por defecto
El playbook opcionalmente provee prompts para entregar credenciales de Tailscale, Netdata y SIDING. Por defecto
el playbook no levanta un mock de CAS, que es necesario para instalaciones sin acceso al SSO UC.

También se provee un script más ligero en [just](./justfile), que principalmente está pensado para su uso en
junto al sistema de [Continuous Deployment](./.github/workflows/deploy.yml) del repositorio. Sin embargo,
dado un entorno ya configurado de Docker Compose, este puede ser utilizado para levantar un servidor independiente,
dado un entorno ya configurado de Docker Compose, este puede ser utilizado para levantar un servidor independiente,
incluyendo uno que utilice un SSO mock.

Abajo se entregan instrucciones manuales de deploy.
Expand All @@ -117,17 +118,20 @@ Abajo se entregan instrucciones manuales de deploy.
El ambiente de staging está diseñado para testear las nuevas versiones del planner en un ambiente real antes de pasar a producción.

En primer lugar, es necesario generar manualmente los archivos `.env` y reemplazar los valores según corresponda para cada servicio utilizando los ejemplos ubicados en cada carpeta:

- _API_ → `backend/.env.staging.template`
- _servidor web_ → `frontend/.env.staging.template`
- _base de datos_ → `database/.env.staging.template`

Luego, se debe crear el volumen de Caddy con `docker volume create caddy_data`.

Ahora, para correr la aplicación utilizando un servidor mock de **CAS externo** se debe:

1. Definir las variables `CAS_SERVER_URL` y `CAS_LOGIN_REDIRECTION_URL` en `backend/.env` con la URL del servidor externo.
2. Levantar los contenedores con `docker compose up planner -d --build` desde la raíz del repositorio.

Alternativamente, para correr la aplicación utilizando un servidor mock de **CAS local**:

1. Dejar las variables `CAS_SERVER_URL` y `CAS_LOGIN_REDIRECTION_URL` en `backend/.env` con los valores predeterminados del archivo de ejemplo `.env.staging.template`.
2. Luego, es necesario generar el archivo `cas-mock-users.json` en `cas-mock/data` a partir del ejemplo `cas-mock-users.json.example`.
3. Levantar los contenedores con `docker compose up -d --build` desde la raíz del repositorio.
Expand All @@ -137,22 +141,24 @@ Finalmente, se puede detener la app con `docker compose down` desde la raíz del
### Deployment manual: Producción

El ambiente de producción es manejado por la universidad de forma interna, por lo que aquí se detallan las **instrucciones para desplegar el planner** de forma manual:
1. Se deben crear tres archivos `.env`, uno por cada servicio y dentro de su respectiva carpeta:
- `backend/.env` a partir del ejemplo `backend/.env.production.template` (_API_)
- `frontend/.env` a partir del ejemplo `frontend/.env.production.template` (_servidor web_).
- `database/.env` a partir del ejemplo `database/.env.production.template` (_base de datos_).

1. Se debe crear el archivo `.env` para la API. En particular, crear `backend/.env` a partir del ejemplo `backend/.env.production.template`.

2. Reemplazar los valores de las variables de entorno según corresponda en todos los archivos `.env` creados. **IMPORTANTE:** no olvidar modificar la variable `JWT_SECRET` en `backend/.env` y otras variables que puedan contener secretos para evitar vulnerabilidades de seguridad.

- Para generar una clave `JWT_SECRET` segura y aleatoria se puede utilizar el comando `openssl rand -base64 32`.

3. Se debe crear el volumen donde Caddy guardará los certificados SSL con `docker volume create caddy_data`.
4. Levantar los contenedores con `docker compose up planner -d --build` desde la raíz del repositorio. Requiere _Docker_ y _Docker Compose_ instalados en la máquina.
5. Revisar el estado de los contenedores con `docker ps` o `docker container ls`.
6. Finalmente, se puede detener la app con `docker compose down` desde la misma ubicación.

Nota: los comandos podrían variar ligeramente dependiendo del sistema operativo y versión de *Docker Compose*. En particular, podría ser necesario utilizar `docker-compose` en vez de `docker compose` y `sudo docker compose` en vez de `docker compose`.
Nota: los comandos podrían variar ligeramente dependiendo del sistema operativo y versión de _Docker Compose_. En particular, podría ser necesario utilizar `docker-compose` en vez de `docker compose` y `sudo docker compose` en vez de `docker compose`.

---

## Equipo

<table>
<tbody>
<tr>
Expand All @@ -165,7 +171,6 @@ Nota: los comandos podrían variar ligeramente dependiendo del sistema operativo
</tbody>
</table>


Además del equipo núcleo, nos apoyan los contribuidores al proyecto. Puedes ver [la lista completa de contribuidores aquí.](contributors.md)

## Licencia
Expand Down
15 changes: 15 additions & 0 deletions backend/.env.default
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
################################################################################################
# No es necesario modificar este archivo durante el proceso de deploy. #
# #
# Nota para los desarrolladores: #
# Aquí van las variables de entorno para producción que NO contienen secretos pero requieren #
# ser definidas antes de levantar el contenedor. Si una variable se utiliza en el código, #
# entonces debe ser definida en el archivo `settings.py` en vez de aquí. #
# Para desarrollo, se sobreescriben estas variables en el archivo `.env`. #
################################################################################################

# Variable requerida para configurar Prisma.
DATABASE_URL=postgresql://postgres:postgres@db:5432/postgres?schema=public

# Variable requerida para definir el ambiente de ejecución.
PYTHON_ENV=production
9 changes: 9 additions & 0 deletions backend/.env.development.template
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@

# In development mode, use a local server instead of the production URL.
PLANNER_URL="http://localhost:3000"

# URL to the CAS server endpoint.
Expand All @@ -7,11 +9,15 @@ PLANNER_URL="http://localhost:3000"
# - The user's browser is redirected here when they request to log in.
# If the URL the user is redirected to is different to the URL used to verify the
# tokens, the `CAS_LOGIN_REDIRECTION_URL` variable should be set to override it.
#
# In development, use a local CAS mock server.
CAS_SERVER_URL="http://localhost:3004/"
CAS_LOGIN_REDIRECTION_URL=""

# Admin RUT. Is always the only admin and has the power of adding/removing mods.
# There will be no admins if this string is left empty.
#
# In development, make an invalid test RUT be the admin.
ADMIN_RUT="012345678-K"

# JWT secret string. If this secret is leaked, anyone can forge JWT tokens for
Expand All @@ -31,6 +37,9 @@ SIDING_PASSWORD=""
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres?schema=public"

# In development, connect with redis through localhost instead of through the docker network.
REDIS_URI="redis://localhost:6379"

# Avoid updating data as much as possible in development mode.
AUTOSYNC_COURSES="false"
AUTOSYNC_CURRICULUMS="false"
Expand Down
36 changes: 12 additions & 24 deletions backend/.env.production.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@
# Este archivo está pensado para ser copiado con el nombre `.env` y ser usado en producción. #
# Es necesario entregar los valores reales a cada una de las variables definidas abajo #
# antes de levantar los contenedores de la aplicación para que funcione correctamente. #
# #
# Nota para los desarrolladores: #
# La idea es que este archivo sea completamente estático, ya que será manejado por la #
# universidad directamente en la máquina de producción. Por esta razón, solo debe ser usado #
# para definir secretos. Cualquier otra variable (e.g. URL de la bbdd) se ingresa a nivel de #
# código para poder ser modificada con un commit al repo. #
# En particular, las variables del backend usadas en código se definen como predeterminadas #
# en el archivo `settings.py`, mientras que Las variables necesarias para levantar los #
# contenedores van en el archivo `.env.default`. #
###############################################################################################

# URL que apunta al planner.
# --> ejemplo: "https://plan.ing.puc.cl"
#
# NOTA: Incluir `https://` en este URL, de otra manera el token se mandará por HTTP desencriptado.
# PLANNER_URL=""

# URL que apunta al servidor de autenticacion CAS.
# --> ejemplo: "https://sso.uc.cl/cas"
# CAS_SERVER_URL=""

# RUT del administrador.
# Es único y tiene el poder de añadir y remover moderadores.
# Si se deja vacío no existirá administrador.
# --> ejemplo: "012345678-K"
# --> ejemplo: "12345678-K"
# ADMIN_RUT=""

# Secreto para generar y verificar tokens JWT.
Expand All @@ -26,16 +25,5 @@
# JWT_SECRET="mal secreto, REEMPLAZAR ESTO por un buen secreto."

# Credenciales para utilizar el webservice de Siding.
# SIDING_USERNAME="cambiar_esta_variable"
# SIDING_PASSWORD="cambiar_esta_variable"

# No debería ser necesario modificar esta variable, a menos que se modifiquen las credenciales
# de la base de datos. En tal caso considerar la siguiente estructura:
# "postgresql://USER:PASSWORD@HOST:PORT/DATABASE"
DATABASE_URL="postgresql://postgres:postgres@db:5432/postgres?schema=public"

# No debería ser necesario modificar esta variable.
REDIS_URI="redis://redis:6379/0"

# Don't remove
PYTHON_ENV="production"
# SIDING_USERNAME="<usuario de siding>"
# SIDING_PASSWORD="<contrasena de siding>"
2 changes: 1 addition & 1 deletion backend/.env.staging.template
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# URL que apunta al planner.
PLANNER_URL="http://localhost"
PLANNER_URL="https://mallastest.ing.uc.cl"

# URL que apunta al servidor de autenticacion CAS.
CAS_SERVER_URL="http://cas_mock_server:3004/"
Expand Down
8 changes: 3 additions & 5 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,15 @@ COPY --from=requirements-stage /tmp/requirements.txt /app/requirements.txt
# Install deps from the requirements-stage
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt

# Copy the application code
# TODO: copy only the necessary files
# Copy the application code, including config and env files
COPY ./ /app
WORKDIR /app

# Copy the .env file
COPY .env /app/.env

# Generate the Prisma client
RUN prisma generate

ENV PRE_START_PATH /app/scripts/prestart.sh

# Monitor the app
HEALTHCHECK --start-period=5m CMD curl -f http://localhost:80/health || exit 1
HEALTHCHECK --start-period=5m CMD curl -f http://localhost:80/health || exit 1
17 changes: 6 additions & 11 deletions backend/app/main.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import asyncio
import logging
import random
from typing import TYPE_CHECKING, Annotated, Literal
from typing import Literal

import sentry_sdk
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.params import Depends
from fastapi.routing import APIRoute
from pydantic import BaseModel, Field
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
Expand All @@ -21,11 +20,6 @@
from app.sync.siding.client import client as siding_soap_client
from app.sync.siding.client import get_titles

if TYPE_CHECKING:
from typing import Any

from redis.asyncio import Redis


# Set up operation IDs for OpenAPI
def custom_generate_unique_id(route: APIRoute):
Expand Down Expand Up @@ -128,7 +122,7 @@ class HealthResponse(BaseModel):


@app.get("/health")
async def health(redis: Annotated["Redis[Any]", Depends(get_redis)]) -> HealthResponse:
async def health() -> HealthResponse:
response = HealthResponse()

try:
Expand All @@ -139,9 +133,10 @@ async def health(redis: Annotated["Redis[Any]", Depends(get_redis)]) -> HealthRe
logging.error(f"Database error detected: {e}")

try:
# Check Redis connection
await redis.ping()
response.detail["redis"] = "healthy"
async with get_redis() as redis:
# Check Redis connection
await redis.ping()
response.detail["redis"] = "healthy"
except Exception as e: # noqa: BLE001
logging.error(f"Redis error detected: {e}")

Expand Down
12 changes: 10 additions & 2 deletions backend/app/plan/courseinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
from app.plan.validation.courses.logic import Expr


class ExprRedefine(BaseModel):
"""
Type adapter. When we update to Pydantic 2, use `TypeAdapter` instead.
"""

__root__: Expr


class CourseDetails(BaseModel):
# The unique code identifying this course.
code: str
Expand Down Expand Up @@ -51,12 +59,12 @@ class CourseDetails(BaseModel):
@staticmethod
def from_db(db: Course) -> "CourseDetails":
# Parse and validate dep json
deps = pydantic.parse_raw_as(Expr, db.deps)
deps = pydantic.parse_raw_as(ExprRedefine, db.deps)
return CourseDetails(
code=db.code,
name=db.name,
credits=db.credits,
deps=deps,
deps=deps.__root__,
banner_equivs=db.banner_equivs,
canonical_equiv=db.canonical_equiv,
program=db.program,
Expand Down
Loading
Loading