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

feat(system-server): add sqlite database and barebones HTTP server #12085

Merged
merged 28 commits into from
Feb 6, 2023

Conversation

fsinapi
Copy link
Contributor

@fsinapi fsinapi commented Jan 31, 2023

Overview

This PR adds a SQLite database and an endpoint-less HTTP server to the system-server project.

  • The system server uses a persistent directory to store the database (and in a future PR, the UUID for signing JWT's). The directory defaults to /var/lib/opentrons-system-server but can be overwritten with an environment variable like on the robot-server.
  • The database contains one table, registration, which is intended to store long-term app registrations.
    • The database is configured as specified in RCORE-508 with the addition of a UNIQUE clause for the tuple of (subject, agent, agent-id) in order to simplify the logic for interacting with the database.
  • The database contains a second table, migration, for tracking any future database migrations needed by the system-server.
  • An HTTP server is configured on port 32950 by default.
    • At least based on looking through our repos and probing that port from an SSH session on a robot, this is unused until now.

Test Plan

This can be tested on an OT-2 with make-push since all the new python packages are already on the disk from the robot-server. To test on an OT-3, a new image has to be flashed because many of these libraries are only in /opt/opentrons-robot-server.

After getting this on a robot, ssh in and do the following:

  • Check with `systemctl status opentrons-system-server`` that the service is running

  • Check that /var/lib/opentrons-system-server has been created and system_server.db exists

  • curl a PUT request to localhost:32950/system/refresh and make sure you get the text 'OK' and the persistent DB is generated.

  • Talk to the robot through an app just to make sure the robot-server and update-server are still working fine

  • Test on OT-2

  • Test on OT-3

Changelog

  • Added persistence submodule to create a persistent directory and generate a SQL database
  • Added settings submodule to get environment variable configuration settings
  • Added app_setup and app_state for barebones FastAPI HTTP server configuration, with router.py as a placeholder router that does nothing so far.
  • Added a TEMPORARY endpoint that initializes the persistent directory & database. This is not necessarily safe but it provides an avenue to verify that db generation works correctly.
  • Added an environment variable for OT_SYSTEM_SERVER_persistent_directory to the OT-2 systemd unit file. This has to be added separately in oe-core for OT-3.

Review requests

  • Would it make sense to just get rid of the environment variable settings? I mostly pulled it in because that seems to be how we prefer configuring the robot-server, but since this server already has CLI options I think I might prefer to just put the persistent directory into the CLI options.
    • I came to the conclusion that this is the more elegant way to handle settings that are needed during FastAPI runtime.

Risk assessment

Low, as long as this doesn't interfere with other servers then it has no user-facing effects yet.

@fsinapi fsinapi added the ot3-build Do an OT-3 system build for this branch. label Jan 31, 2023
@fsinapi fsinapi self-assigned this Jan 31, 2023
@codecov
Copy link

codecov bot commented Feb 1, 2023

Codecov Report

Merging #12085 (ef791b4) into edge (ed0e6f3) will decrease coverage by 0.51%.
The diff coverage is 76.43%.

Impacted file tree graph

@@            Coverage Diff             @@
##             edge   #12085      +/-   ##
==========================================
- Coverage   74.48%   73.97%   -0.51%     
==========================================
  Files        2180     2211      +31     
  Lines       59867    61071    +1204     
  Branches     6467     6477      +10     
==========================================
+ Hits        44589    45176     +587     
- Misses      13747    14358     +611     
- Partials     1531     1537       +6     
Flag Coverage Δ
system-server 67.90% <76.43%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
system-server/system_server/__main__.py 0.00% <0.00%> (ø)
system-server/system_server/cli.py 0.00% <0.00%> (ø)
system-server/system_server/_version.py 61.53% <61.53%> (ø)
system-server/system_server/app_setup.py 71.42% <71.42%> (ø)
...ystem-server/system_server/persistence/__init__.py 73.33% <73.33%> (ø)
system-server/system_server/settings/settings.py 77.27% <77.27%> (ø)
system-server/system_server/router.py 85.71% <85.71%> (ø)
...ystem-server/system_server/persistence/database.py 86.36% <86.36%> (ø)
system-server/system_server/app_state.py 86.66% <86.66%> (ø)
system-server/system_server/__init__.py 100.00% <100.00%> (ø)
... and 63 more

@fsinapi fsinapi marked this pull request as ready for review February 1, 2023 16:30
@fsinapi fsinapi requested review from a team as code owners February 1, 2023 16:30
Copy link
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks solid to me!

Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exciting! Various bits of feedback learned from robot-server lessons.

system-server/mypy.ini Outdated Show resolved Hide resolved
system-server/system_server/persistence/tables.py Outdated Show resolved Hide resolved
system-server/system_server/persistence/database.py Outdated Show resolved Hide resolved
system-server/system_server/persistence/tables.py Outdated Show resolved Hide resolved
system-server/system_server/settings/settings.py Outdated Show resolved Hide resolved
system-server/system_server/app_setup.py Outdated Show resolved Hide resolved
system-server/system_server/persistence/tables.py Outdated Show resolved Hide resolved
system-server/system_server/persistence/tables.py Outdated Show resolved Hide resolved
Comment on lines 45 to 46
persistence_directory = await get_persistence_directory(app.state)
await get_sql_engine(app.state, persistence_directory)
Copy link
Contributor

@SyntaxColoring SyntaxColoring Feb 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should call get_persistence_directory() and get_sql_engine() like this.

In robot-server, where these function's definitions are copied from, these aren't normal functions—they're FastAPI dependency functions.

We need to draw a bright line between the two kinds of function and treat them as mutually exclusive. When you call a FastAPI dependency function as if it were a normal function, it's very easy to accidentally subvert static type safety and cause confusing breakage. This is a FastAPI trap that we (and others) have been bitten by before—see #8051.

In principle, I think eagerly initializing the database is the right thing to do, and we're moving in this direction in robot-server (#11615). But our code for this in robot-server is a highly-duplicated mess right now, so I don't think we have a good model for eager initialization just yet.

For the short term, what do you think about doing the default FastAPI thing and let the database be initialized lazily for the first HTTP request that requires it? We got away with that in robot-server for a while.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that makes sense even if it makes me Big Sad.

I'm gonna add a fake little endpoint that depends on the database so it's possible to test the db generation.

Copy link
Contributor

@mcous mcous left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with all of Max's feedback. I also have some specific feedback on the tests added in test_persistent_generation

system-server/Pipfile Outdated Show resolved Hide resolved
system-server/system_server/cli.py Outdated Show resolved Hide resolved
system-server/system_server/persistence/tables.py Outdated Show resolved Hide resolved
assert not expected.exists()


async def test_create_tmpdir(monkeypatch: MonkeyPatch, tmpdir: Path) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this test inappropriately mixes mocking, implementation details, and logic testing. It'll likely be brittle over time and doesn't really test that things work, due to the mocks. It also brings in the entire world of FastAPI.

I recommend restructuring this so that the question "is it going to the expected directory?" is tested without mocks. For example, the suite could have:

  • Test that checks the settings module has the correct directory value
  • Test that checks the persistence module, given a value from settings, creates a directory at the given value
  • Test, with mocks, that checks the settings module and persistence module are wired up to each other properly, but does not test any logic because mocks inherently compromise logic tests
  • Acceptance test that does not use mocks and simply tests that resources are persisted.
    • Thanks to the other tests, we don't really need to check in this test if they're persisted in the correct place, because that's covered by more specific tests

Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One file leakage thing. Other than this, changes since my last review look good. Thanks!

@fsinapi fsinapi merged commit 799ea17 into edge Feb 6, 2023
@fsinapi fsinapi deleted the RCORE-508_system_server_sqlite branch February 6, 2023 20:05
y3rsh added a commit that referenced this pull request Feb 7, 2023
* edge: (116 commits)
  feat(system-server): add sqlite database and barebones HTTP server (#12085)
  feat(ot3): add enableOT3FirmwareUpdates feature flag to gate firmware update functionality. (#12102)
  feat(app): add bare bones hardware section to protocol details (#12099)
  feat(app): Support failed calibrations in the calibration wizard (#12092)
  refactor(docs): clean up Versioning page (#12084)
  refactor(robot-server): Make run and protocol limits configurable at launch (#12094)
  feat(app): add robotServerVersion to display the current robot software version (#12096)
  fix(hardware): do not track tip motor positions (#12093)
  feat(engine): allow calibrateGripper command to save calibration data (#12046)
  feat(app, api-client, react-api-client): delete POC TLC calibration data from overflow menu (#12075)
  fix(api): actually update OT3 instrument calibration offset in cache instrument (#12089)
  fix(robot-server): correct the data returned from instruments endpoint (#12067)
  feat(api): add thermocycler plate lift to hardware controller (#12068)
  fix(app): reference moduleId from result not params (#12077)
  feat(app): create ODD protocol setup page (#12071)
  refactor(api): Deprecate presses and increment args when using PAPI pick_up_tip (#12079)
  fix(ot3): handle multiple responses for a tip action request (#12083)
  refactor(api): touch tip implementation for PAPIv2 engine core (#12053)
  refactor(app): Remove ssid parameter from OnDeviceRouteParams (#11930)
  fix(api): fix broken test in the api hardware controller (#12080)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ot3-build Do an OT-3 system build for this branch.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants