Skip to content

Commit e85f780

Browse files
authored
Implement database schema (#381)
# Purpose Closes #321 # Warning: Breaking Changes - All GS members will need to install PostgreSQL by following the instructions in the `POSTGRESQL_SETUP.md` to run the backend - Dropping support for using Windows as the development environment. Use WSL instead if you are on Windows. See in the instructions in the `README.md`. Make sure to install Ubuntu 22 as the distro of choice as Ubuntu 24 has issues with installing Python packages in editable mode. # New Changes - Implement database schema for non auth related tables - Switch the pytest workflow runner to use only Ubuntu - Remove Docker setup instructions from the README as it is was unused and there doesn't make sense to spend the effort to maintain it. - Add PostgreSQL setup instructions - Add database configuration files - Create tests for database tables - Create `MainCommands` get endpoint under the `/api/v1/mcc/main-commands/` path - Add some data for the `MainCommands` - Make schemas, tables and data for `MainCommands` generate automatically. The database must be created manually - Fix minor README issues # Testing - Create unit tests for all tables - Test the MainCommands get endpoint manually: ![Screenshot from 2025-04-13 13-02-59](https://github.com/user-attachments/assets/bfe74a98-e359-47c5-9921-98651902865c) - Validate that the MainCommands exist in the database: ![image](https://github.com/user-attachments/assets/8b888b06-d8c1-4878-a498-cc84f3b74d2a) # Outstanding Changes - Add auth related tables once we determine how to setup auth - Improve the table tests to test data validation and more complex relations. - Improve the configuration files. This will be handled by #335 - Add loguru to SQLModel logger. This will be handled by #380 - Pull `MainCommands` and `MainTelemetry` from a configuration file and have it synced with the OBC - Add data validation for `MainCommands` table. This will be handled by #356 - Determine what `subtype` for packets means. This is an CSDC requirement but we can easily add this to the database later. - Make `Commands.params` match with `MainCommands.params` - Make `Telemetry.value` match with `MainTelemetry.params` - Split up the README into separate READMEs for GS and Firmware where instructions and data doesn't overlap - Add test for `MainCommand` get endpoint
1 parent 715c6fc commit e85f780

32 files changed

+1061
-50
lines changed

.github/workflows/pytest.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ on:
88

99
jobs:
1010
pytest:
11-
runs-on: ${{ matrix.os }}
11+
runs-on: ubuntu-latest
1212

1313
strategy:
1414
matrix:
15-
os: [ubuntu-latest, windows-latest]
1615
python-version: ['3.11']
1716

1817
steps:
@@ -25,6 +24,8 @@ jobs:
2524

2625
- name: Install dependencies
2726
run: |
27+
sudo apt update
28+
sudo apt install -y postgresql
2829
python -m pip install --upgrade pip
2930
pip install -r requirements.txt
3031
pip install -e .

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ compile_commands.json
6464
*.sw?
6565

6666
.env
67+
*.db
6768

6869
/build*
6970

README.md

Lines changed: 22 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -41,49 +41,8 @@ Download Code Composer Studio (CCS): https://www.ti.com/tool/CCSTUDIO. This will
4141

4242
Download UniFlash here: https://www.ti.com/tool/UNIFLASH#downloads. This will be used for flashing the RM46.
4343

44-
#### Docker Development Environment
45-
46-
It's **highly recommended** that you set up your development environment using Docker and VSCode, especially if you're new to software development. If you follow the instructions in this section, you can skip the **Windows/MacOS/Linux** sections. If you know what you're doing, feel free to set up your dev environment however you like using the instructions in the **Windows/MacOS/Linux** sections for reference. However, there may be a lack of support from other leads/members who don't use the same setup.
47-
48-
##### Docker Desktop Installation & Configuration
49-
50-
1. Install Docker Desktop App from [this link](https://www.docker.com/products/docker-desktop/)
51-
- You can choose to sign-up/create an account but it's not required. You can also skip the "Tell-us about what you do" section.
52-
2. Open Docker Desktop and click on `Dev Environments` from the side-panel
53-
- Click on create on `Create +` in the top-right corner.
54-
3. Setting up the repo
55-
- Name the Environment as desired
56-
- For the `Choose source` option, select `Local directory` and then select the `OBC-firmware` repository folder that you cloned earlier.
57-
- Click `Continue`
58-
- Once the container is created, you should be able to open the container in VSCode. If you have VSCode, you can press `Open in VSCode`. If you don't have VSCode, you can get it here: https://code.visualstudio.com/download
59-
60-
##### Installing Dependencies
61-
62-
Once you open the docker instance, open a terminal in VSCode and run the following commands. The dollar sign in your terminal should be prefaced by something like this: `root ➜ /com.docker.devenvironments.code (main ✗)`.
63-
64-
This command opens a terminal in VSCode: `` Ctrl + Shift + ` ``
65-
66-
Enter these commands in your terminal:
67-
```sh
68-
sudo apt-get update
69-
sudo apt-get install -y python3-pip build-essential cmake gcc-multilib g++-multilib curl
70-
pip3 install -r requirements.txt
71-
curl -fsSL https://deno.land/install.sh | sh # Deno is required for pre-commit
72-
pre-commit install
73-
```
74-
75-
##### Testing The Container Build
76-
77-
To test whether your Dev environment has been set up correctly run the commands in the **Building** section. The OBC firmware and test builds should pass. All tests should succeed.
78-
79-
**Note**: The docker container uses pre-configured git (one added to the original OS path by the user). So you should be able to pull and push to the OBC repo as necessary.
80-
81-
**Tip**: Use the `git config --list` command on the VsCode terminal to confirm your git info.
82-
8344
#### **Windows**
8445

85-
Skip this section if you set up a Docker development environment.
86-
8746
1. Download WSL2: https://learn.microsoft.com/en-us/windows/wsl/install
8847

8948
2. In WSL2, run the following:
@@ -117,11 +76,14 @@ Skip this section if you set up a Docker development environment.
11776
- Once your PATH is set up and pre-commit is installed you can use `pre-commit run --all-files` to format all of your files before committing
11877
**Note:** pre-commit is used to format your code whenever you make a commit.
11978

120-
You'll be using WSL2 primarily for building the firmware and running tests.
79+
You'll be using WSL2 for all development.
12180

122-
#### **MacOS**
81+
5. Setup the PostgreSQL database
12382

124-
Skip this section if you set up a Docker development environment.
83+
This setup is only required for GS members. Please follow the instructions located in [POSTGRESQL_SETUP.md](gs/POSTGRESQL_SETUP.md)
84+
85+
86+
#### **MacOS**
12587

12688
1. Install required build tools (CMake, Make, gcc)
12789

@@ -131,7 +93,7 @@ brew install make
13193
brew install gcc
13294
```
13395

134-
2. Install Python 3.11 and setup Python virtual environment (Only required for Backend devs)
96+
2. Install Python 3.11 and setup Python virtual environment (Only required for GS devs)
13597

13698
Run the following commands in the OBC-firmware directory:
13799

@@ -150,10 +112,12 @@ curl -fsSL https://deno.land/install.sh | sh # Deno is required for pre-commit
150112
pip install -r requirements.txt # You may want to create a Python virtual env before this if you haven't already
151113
pre-commit install
152114
```
115+
4. Setup the PostgreSQL database
153116

154-
#### **Linux**
117+
This setup is only required for GS members. Please follow the instructions located in [POSTGRESQL_SETUP.md](gs/POSTGRESQL_SETUP.md)
155118

156-
Skip this section if you set up a Docker development environment.
119+
120+
#### **Linux**
157121

158122
1. Install required build tools (CMake, Make, gcc)
159123

@@ -162,7 +126,7 @@ sudo apt-get update
162126
sudo apt-get install build-essential gcc-multilib g++-multilib curl
163127
```
164128

165-
2. Install Python 3.11 and setup Python virtual environment (Only required for Backend devs)
129+
2. Install Python 3.11 and setup Python virtual environment (Only required for GS devs)
166130

167131
Run the following commands in the OBC-firmware directory:
168132

@@ -182,6 +146,10 @@ pip install -r requirements.txt # You may want to create a Python virtual env be
182146
pre-commit install
183147
```
184148

149+
4. Setup the PostgreSQL database
150+
151+
This setup is only required for GS members. Please follow the instructions located in [POSTGRESQL_SETUP.md](gs/POSTGRESQL_SETUP.md)
152+
185153
### Building
186154

187155
#### **OBC Firmware**
@@ -296,6 +264,12 @@ We use Code Composer Studio for debugging the firmware. **TODO**: Write a tutori
296264

297265
To run the frontend, you will need Deno 2 installed which was installed in the pre-commit setup instructions above.
298266

267+
#### **Setting up the Frontend **
268+
```sh
269+
cd gs/frontend
270+
deno install --frozen
271+
```
272+
299273
#### **Running the ARO Frontend**
300274

301275
```sh

gs/POSTGRESQL_SETUP.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# PostgreSQL Setup
2+
3+
## Table of Contents
4+
5+
- [Installation](#installation)
6+
- [Database Setup](#database-setup)
7+
- [Environment Variable Setup](#environment-variable-setup)
8+
- [Sources](#sources)
9+
10+
**[Back to top](#table-of-contents)**
11+
12+
## Installation
13+
14+
Run the following command dependant on your setup.
15+
If you have Windows, install WSL. See the instructions in the top level [README.md](../../README.md)
16+
17+
### Linux/WSL
18+
19+
```sh
20+
sudo apt update
21+
sudo apt install postgresql-16
22+
```
23+
24+
### MacOS
25+
26+
```sh
27+
brew install postgresql@16
28+
brew services start postgresql
29+
```
30+
31+
**[Back to top](#table-of-contents)**
32+
33+
## Database Setup
34+
35+
Run `sudo -u postgres psql --version` to check that it was installed properly. It should print that major version is 16.
36+
37+
Below are the commands to setup PostgreSQL for the ground station
38+
```sh
39+
sudo -u postgres psql # Connect to the PostgreSQL CLI
40+
CREATE USER username WITH PASSWORD 'password' SUPERUSER; # Change username to your user on the machine and password to a strong password
41+
# Log out of this session by pressing Ctrl + D
42+
```
43+
Log back in by running `psql` if username you created above matches the current user, you don't need to log in.
44+
Otherwise, you will need to run `psql -U username` and then enter the password created above to proceed.
45+
```sh
46+
CREATE DATABASE gs; # gs database
47+
\c gs; # Connect to the gs database
48+
```
49+
50+
**[Back to top](#table-of-contents)**
51+
52+
## Environment Variable Setup
53+
54+
Find the `gs/backend/config/template.env` and create a copy of it in the same directory with the name `.env`
55+
Inside your newly created `.env` file, put your username and password created above inside the quotes for `GS_DATABASE_USER` and `GS_DATABASE_PASSWORD` respectively.
56+
57+
In the end your `.env` file, should look like this:
58+
```sh
59+
GS_DATABASE_USER="username" # replace username with your created username
60+
GS_DATABASE_PASSWORD="password" # replace password with your created password above
61+
GS_DATABASE_LOCATION="localhost" # Change this if using a remote server
62+
GS_DATABASE_PORT="5432" # Default PostgreSQL port. Change if needed
63+
GS_DATABASE_NAME="gs" # Name of the database. NOTE: Make sure to create this manually before running the backend of the first time
64+
```
65+
66+
Note: You can choose to remove the first to lines of the `.env` that start with \# as those lines are comments.
67+
68+
Now, you can start the backend as by running `fastapi dev gs/backend/main.py` from the top level directory to run in development mode.
69+
70+
**[Back to top](#table-of-contents)**
71+
72+
## Sources
73+
74+
- [How to Install and Setup PostgreSQL on Ubuntu 20.04 | Step-by-Step](https://www.cherryservers.com/blog/how-to-install-and-setup-postgresql-server-on-ubuntu-20-04)
75+
- [Install and configure PostgreSQL](https://documentation.ubuntu.com/server/how-to/databases/install-postgresql/index.html)
76+
- [How To Install PostgreSQL on Ubuntu 20.04 \[Quickstart\]](https://www.digitalocean.com/community/tutorials/how-to-install-postgresql-on-ubuntu-20-04-quickstart)
77+
78+
**[Back to top](#table-of-contents)**

gs/backend/api/backend_setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from gs.backend.api.v1.aro.endpoints.user import aro_user_router
88
from gs.backend.api.v1.mcc.endpoints.aro_requests import aro_requests_router
99
from gs.backend.api.v1.mcc.endpoints.commands import commands_router
10+
from gs.backend.api.v1.mcc.endpoints.main_commands import main_commands_router
1011
from gs.backend.api.v1.mcc.endpoints.telemetry import telemetry_router
1112

1213

@@ -24,6 +25,7 @@ def setup_routes(app: FastAPI) -> None:
2425
app.include_router(commands_router, prefix=f"{mcc_prefix}/commands")
2526
app.include_router(telemetry_router, prefix=f"{mcc_prefix}/telemetry")
2627
app.include_router(aro_requests_router, prefix=f"{mcc_prefix}/requests")
28+
app.include_router(main_commands_router, prefix=f"{mcc_prefix}/main-commands")
2729

2830

2931
def setup_middlewares(app: FastAPI) -> None:

gs/backend/api/lifespan.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,15 @@
33

44
from fastapi import FastAPI
55

6+
from gs.backend.data.database.engine import get_db_session, setup_database
7+
from gs.backend.data.resources.utils import add_main_commands
8+
69

710
@asynccontextmanager
811
async def lifespan(_: FastAPI) -> AsyncGenerator[None, None]:
912
"""Lifecycle event for the FastAPI app."""
13+
# Must all the get_db_session each time when pass it into a separate function.
14+
# Otherwise, will get transaction is inactive error
15+
setup_database(get_db_session())
16+
add_main_commands(get_db_session())
1017
yield
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from fastapi import APIRouter, Depends
2+
from sqlmodel import Session, select
3+
4+
from gs.backend.api.v1.mcc.models.responses import MainCommandsResponse
5+
from gs.backend.data.database.engine import get_db_session
6+
from gs.backend.data.tables.main_tables import MainCommand
7+
8+
main_commands_router = APIRouter(tags=["MCC", "Main Commands"])
9+
10+
11+
@main_commands_router.get("/")
12+
async def get_main_commands(db_session: Session = Depends(get_db_session)) -> MainCommandsResponse:
13+
"""
14+
@brief Gets the main commands that are available for the MCC
15+
"""
16+
main_commands_query = select(MainCommand)
17+
items = list(db_session.exec(main_commands_query).all())
18+
return MainCommandsResponse(data=items)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from pydantic import BaseModel
2+
3+
from gs.backend.data.tables.main_tables import MainCommand
4+
5+
6+
class MainCommandsResponse(BaseModel):
7+
"""
8+
The main commands response model.
9+
"""
10+
11+
data: list[MainCommand]

gs/backend/config/__init__.py

Whitespace-only changes.

gs/backend/config/config.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# TODO:(335) Improve loading the configuration
2+
from os import environ
3+
from typing import Final
4+
5+
from dotenv import load_dotenv
6+
7+
load_dotenv()
8+
9+
10+
# TODO: Make these throw an exception if they are None
11+
GS_DATABASE_USER = environ.get("GS_DATABASE_USER")
12+
GS_DATABASE_PASSWORD = environ.get("GS_DATABASE_PASSWORD")
13+
GS_DATABASE_LOCATION = environ.get("GS_DATABASE_LOCATION")
14+
GS_DATABASE_PORT = environ.get("GS_DATABASE_PORT")
15+
GS_DATABASE_NAME = environ.get("GS_DATABASE_NAME")
16+
17+
DATABASE_CONNECTION_STRING: Final[
18+
str
19+
] = f"postgresql+psycopg2://{GS_DATABASE_USER}:{GS_DATABASE_PASSWORD}@{GS_DATABASE_LOCATION}:{GS_DATABASE_PORT}/{GS_DATABASE_NAME}"

0 commit comments

Comments
 (0)