-
Notifications
You must be signed in to change notification settings - Fork 106
versionchooser: move from connexion/aiohttp to fastapi #3435
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
Merged
joaomariolago
merged 3 commits into
bluerobotics:master
from
nicoschmdt:aiohttp-to-fastapi
Jul 29, 2025
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# pylint: disable=W0406 | ||
from .app import application | ||
|
||
__all__ = ["application"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from os import path | ||
|
||
from commonwealth.utils.apis import GenericErrorHandlingRoute, PrettyJSONResponse | ||
from fastapi import FastAPI | ||
from fastapi.responses import HTMLResponse | ||
from fastapi.staticfiles import StaticFiles | ||
from fastapi_versioning import VersionedFastAPI | ||
|
||
# Routers | ||
from api.v1.routers import ( | ||
index_router_v1, | ||
docker_router_v1, | ||
version_router_v1, | ||
bootstrap_router_v1, | ||
) | ||
|
||
application = FastAPI( | ||
title="Version Chooser API", | ||
description="Version Chooser is the BlueOS service responsible for managing BlueOS versions", | ||
default_response_class=PrettyJSONResponse, | ||
) | ||
application.router.route_class = GenericErrorHandlingRoute | ||
|
||
# API v1 | ||
application.include_router(index_router_v1) | ||
application.include_router(docker_router_v1) | ||
application.include_router(version_router_v1) | ||
application.include_router(bootstrap_router_v1) | ||
|
||
|
||
application = VersionedFastAPI(application, prefix_format="/v{major}.{minor}", enable_latest=True) | ||
|
||
|
||
@application.get("/", status_code=200) | ||
async def root() -> HTMLResponse: | ||
html_content = """ | ||
<html> | ||
<head> | ||
<title>Version Chooser</title> | ||
</head> | ||
</html> | ||
""" | ||
return HTMLResponse(content=html_content) | ||
|
||
|
||
# Mount static files | ||
application.mount("/static", StaticFiles(directory=path.join(path.dirname(__file__), "static")), name="static") |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# pylint: disable=W0406 | ||
from .bootstrap import bootstrap_router_v1 | ||
from .index import index_router_v1 | ||
from .docker import docker_router_v1 | ||
from .version import version_router_v1 | ||
|
||
__all__ = ["bootstrap_router_v1", "index_router_v1", "docker_router_v1", "version_router_v1"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from typing import Any | ||
|
||
import aiodocker | ||
from fastapi import APIRouter, Depends, status | ||
from fastapi_versioning import versioned_api_route | ||
from pydantic import BaseModel | ||
|
||
from utils.chooser import VersionChooser | ||
|
||
bootstrap_router_v1 = APIRouter( | ||
prefix="/bootstrap", | ||
tags=["bootstrap_v1"], | ||
route_class=versioned_api_route(1, 0), | ||
responses={status.HTTP_404_NOT_FOUND: {"description": "Not found"}}, | ||
) | ||
|
||
|
||
class BootstrapRequest(BaseModel): | ||
tag: str | ||
|
||
|
||
async def get_docker_client(): | ||
async with aiodocker.Docker() as docker_client: | ||
yield VersionChooser(docker_client) | ||
|
||
|
||
@bootstrap_router_v1.get("/current", summary="Return the current running version of BlueOS-bootstrap") | ||
async def get_bootstrap_version(version_chooser: VersionChooser = Depends(get_docker_client)) -> Any: | ||
return await version_chooser.get_bootstrap_version() | ||
|
||
|
||
@bootstrap_router_v1.post("/current", summary="Sets the current version of BlueOS-bootstrap to a new tag") | ||
async def set_bootstrap_version( | ||
request: BootstrapRequest, version_chooser: VersionChooser = Depends(get_docker_client) | ||
) -> Any: | ||
return await version_chooser.set_bootstrap_version(request.tag) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from typing import Any | ||
|
||
from fastapi import APIRouter, status | ||
from fastapi_versioning import versioned_api_route | ||
|
||
|
||
from docker_login import ( | ||
DockerLoginInfo, | ||
get_docker_accounts, | ||
make_docker_login, | ||
make_docker_logout, | ||
) | ||
|
||
docker_router_v1 = APIRouter( | ||
prefix="/docker", | ||
tags=["docker_v1"], | ||
route_class=versioned_api_route(1, 0), | ||
responses={status.HTTP_404_NOT_FOUND: {"description": "Not found"}}, | ||
) | ||
|
||
|
||
@docker_router_v1.post("/login", summary="Login Docker daemon to a registry") | ||
async def docker_login(request: DockerLoginInfo) -> None: | ||
return make_docker_login(request) | ||
|
||
|
||
@docker_router_v1.post("/logout", summary="Logout Docker daemon from a registry") | ||
async def docker_logout(request: DockerLoginInfo) -> Any: | ||
return make_docker_logout(request) | ||
nicoschmdt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
@docker_router_v1.get("/accounts", summary="Get the list of accounts logged in") | ||
def docker_accounts() -> Any: | ||
return get_docker_accounts() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from fastapi import APIRouter, status | ||
from fastapi.responses import RedirectResponse | ||
from fastapi_versioning import versioned_api_route | ||
|
||
index_router_v1 = APIRouter( | ||
tags=["index_v1"], | ||
route_class=versioned_api_route(1, 0), | ||
responses={status.HTTP_404_NOT_FOUND: {"description": "Not found"}}, | ||
) | ||
|
||
|
||
@index_router_v1.get("/", status_code=200) | ||
async def root() -> RedirectResponse: | ||
""" | ||
Root endpoint for the Version Chooser API V1. | ||
""" | ||
return RedirectResponse(url="/v1.0/docs") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
from typing import Any | ||
|
||
import aiodocker | ||
from fastapi import APIRouter, Depends, File, UploadFile, status | ||
from fastapi_versioning import versioned_api_route | ||
from pydantic import BaseModel | ||
|
||
from utils.chooser import VersionChooser | ||
|
||
version_router_v1 = APIRouter( | ||
prefix="/version", | ||
tags=["version_v1"], | ||
route_class=versioned_api_route(1, 0), | ||
responses={status.HTTP_404_NOT_FOUND: {"description": "Not found"}}, | ||
) | ||
|
||
|
||
class DockerImageIdentifier(BaseModel): | ||
repository: str | ||
tag: str | ||
|
||
|
||
async def get_docker_client(): | ||
async with aiodocker.Docker() as docker_client: | ||
yield VersionChooser(docker_client) | ||
|
||
|
||
@version_router_v1.get( | ||
"/current", summary="Return the current running version of BlueOS", status_code=status.HTTP_200_OK | ||
) | ||
async def get_version(version_chooser: VersionChooser = Depends(get_docker_client)) -> Any: | ||
return await version_chooser.get_version() | ||
|
||
|
||
@version_router_v1.post("/current", summary="Sets the current version of BlueOS to a new tag") | ||
async def set_version( | ||
request: DockerImageIdentifier, version_chooser: VersionChooser = Depends(get_docker_client) | ||
) -> Any: | ||
return await version_chooser.set_version(request.repository, request.tag) | ||
|
||
|
||
@version_router_v1.post("/pull", summary="Pulls a version from dockerhub") | ||
async def pull_version( | ||
request: DockerImageIdentifier, version_chooser: VersionChooser = Depends(get_docker_client) | ||
) -> Any: | ||
return await version_chooser.pull_version(request.repository, request.tag) | ||
|
||
|
||
@version_router_v1.delete("/delete", summary="Delete the selected version of BlueOS") | ||
async def delete_version( | ||
request: DockerImageIdentifier, version_chooser: VersionChooser = Depends(get_docker_client) | ||
) -> Any: | ||
return await version_chooser.delete_version(request.repository, request.tag) | ||
|
||
|
||
@version_router_v1.get("/available/local", summary="Returns available local versions") | ||
async def get_available_local_versions(version_chooser: VersionChooser = Depends(get_docker_client)) -> Any: | ||
return await version_chooser.get_available_local_versions() | ||
|
||
|
||
@version_router_v1.get( | ||
"/available/{repository}/{image}", summary="Returns available versions, both locally and in dockerhub" | ||
) | ||
async def get_available_versions( | ||
repository: str, image: str, version_chooser: VersionChooser = Depends(get_docker_client) | ||
) -> Any: | ||
return await version_chooser.get_available_versions(f"{repository}/{image}") | ||
|
||
|
||
@version_router_v1.post("/load", summary="Load a docker tar file") | ||
async def load(file: UploadFile = File(...), version_chooser: VersionChooser = Depends(get_docker_client)) -> Any: | ||
sourcery-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
data = await file.read() | ||
return await version_chooser.load(data) | ||
|
||
|
||
@version_router_v1.post("/restart", summary="Restart the currently running docker container") | ||
async def restart(version_chooser: VersionChooser = Depends(get_docker_client)) -> Any: | ||
return await version_chooser.restart() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import argparse | ||
from dataclasses import dataclass | ||
|
||
|
||
@dataclass | ||
class CommandLineArgs: | ||
""" | ||
Represents command-line arguments for Version Chooser. | ||
|
||
Attributes: | ||
debug (bool): Enable debug mode | ||
host (str): Host to server version-chooser on | ||
port (int): Port to server version-chooser on | ||
""" | ||
|
||
debug: bool | ||
host: str | ||
port: int | ||
|
||
@staticmethod | ||
def from_args() -> "CommandLineArgs": | ||
parser = argparse.ArgumentParser(description="Version Chooser Manager service.") | ||
|
||
parser.add_argument("--debug", action="store_true", default=False, help="Enable debug mode") | ||
parser.add_argument("--host", type=str, default="0.0.0.0", help="Host to server version-chooser on") | ||
parser.add_argument("--port", type=int, default=8081, help="Port to server version-chooser on") | ||
|
||
args = parser.parse_args() | ||
client_args = CommandLineArgs(debug=args.debug, host=args.host, port=args.port) | ||
|
||
return client_args | ||
nicoschmdt marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.