Skip to content

Commit

Permalink
feat(hub): begin adding methods for compiling analysis image URL
Browse files Browse the repository at this point in the history
  • Loading branch information
brucetony committed Apr 9, 2024
1 parent e4256ef commit b74db09
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 52 deletions.
8 changes: 7 additions & 1 deletion hub_adapter/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,13 @@ async def verify_idp_token(token: str = Security(idp_oauth2_scheme)) -> dict:
async def get_hub_token() -> dict:
"""Automated method for getting a token from the central Hub service."""
hub_user, hub_pwd = hub_adapter_settings.HUB_USERNAME, hub_adapter_settings.HUB_PASSWORD
payload = {"username": hub_user, "password": hub_pwd}
payload = {"username": hub_user, "password": hub_pwd} # For testing

# TODO move to robot
# robot_user, robot_secret = hub_adapter_settings.HUB_ROBOT_USER, hub_adapter_settings.HUB_ROBOT_SECRET
# {"grant_type": 'robot_credentials', "id": '<robot-id>|<robot-name>', "secret": '<robot-secret>'}
# payload = {"grant_type": 'robot_credentials', "id": robot_user, "secret": robot_secret}

token_route = hub_adapter_settings.HUB_AUTH_SERVICE_URL.rstrip("/") + "/token"
resp = httpx.post(token_route, data=payload)

Expand Down
6 changes: 4 additions & 2 deletions hub_adapter/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ class Settings(BaseModel):
API_CLIENT_SECRET: str = os.getenv("API_CLIENT_SECRET") # Not used currently

# Hub
HUB_AUTH_SERVICE_URL: str = os.getenv("HUB_AUTH_SERVICE_URL", "https://auth.privateaim.net")
HUB_SERVICE_URL: str = os.getenv("HUB_SERVICE_URL", "https://api.privateaim.net")
HUB_AUTH_SERVICE_URL: str = os.getenv("HUB_AUTH_SERVICE_URL", "https://privateaim.net/auth")
HUB_SERVICE_URL: str = os.getenv("HUB_SERVICE_URL", "https://privateaim.net/core")
HUB_USERNAME: str = os.getenv("HUB_USERNAME")
HUB_PASSWORD: str = os.getenv("HUB_PASSWORD")
HUB_ROBOT_USER: str = os.getenv("HUB_ROBOT_USER")
HUB_ROBOT_SECRET: str = os.getenv("HUB_ROBOT_SECRET")


hub_adapter_settings = Settings()
Expand Down
15 changes: 15 additions & 0 deletions hub_adapter/models/hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,18 @@ class ListAnalysisNodes(BaseModel):

class ListContainers(BaseModel):
containers: list[ContainerData]


class RegistryProject(BaseHubResponse):
name: str | None = None
type: str
public: bool
external_name: str | None = None
external_id: str | None = None
webhook_name: str | None = None
webhook_exists: bool | None = None
account_name: str | None = None
account_secret: str | None = None
registry_id: uuid.UUID | None = None
registry: Registry | None = None
realm_id: uuid.UUID | None = None
177 changes: 128 additions & 49 deletions hub_adapter/routers/hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,68 @@
import uuid
from typing import Annotated

from fastapi import APIRouter, Query, Path, Depends, Security
from fastapi import APIRouter, Query, Path, Depends
from starlette import status
from starlette.requests import Request
from starlette.responses import Response
from starlette.responses import Response, RedirectResponse

from hub_adapter.auth import add_hub_jwt, verify_idp_token, idp_oauth2_scheme_pass, httpbearer
from hub_adapter.auth import add_hub_jwt
from hub_adapter.conf import hub_adapter_settings
from hub_adapter.core import route
from hub_adapter.models.hub import Project, AllProjects, ApprovalStatus, AnalysisOrProjectNode, \
ListAnalysisOrProjectNodes, \
AnalysisNode, ListAnalysisNodes
from hub_adapter.models.podorc import ImageDataResponse
AnalysisNode, ListAnalysisNodes, RegistryProject

hub_router = APIRouter(
dependencies=[Security(verify_idp_token), Depends(add_hub_jwt), Security(idp_oauth2_scheme_pass),
Security(httpbearer)],
# dependencies=[Security(verify_idp_token), Depends(add_hub_jwt), Security(idp_oauth2_scheme_pass),
# Security(httpbearer)],
dependencies=[Depends(add_hub_jwt)],
tags=["Hub"],
responses={404: {"description": "Not found"}},
)


@hub_router.get("/hub/images", response_model=ImageDataResponse)
async def get_images():
"""Return list of images for the frontend."""
# TODO: replace with data from https://api.privateaim.net/master-images

dummy_data = {
"pullImages": [
{
"id": "59081687-3dfe-46cf-afb5-07c562a002af",
"train_class_id": "choochoo",
"repo_tag": "0.5.23-pull",
"job_id": "49e79b47-686b-4fb8-9259-fd0035b0b7f6",
"status": "pulled"
}
],
"pushImages": [
{
"id": "4a941577-46ce-4220-8ca0-181cf45abe29",
"train_class_id": "choochoo",
"repo_tag": "latest",
"job_id": "5efabb71-ba5d-4d00-9ed4-f27eb6a52e8f",
"status": "waiting_to_push"
}
],
}
return dummy_data


@hub_router.get("/hub/vault/status")
async def get_vault_status():
"""Spoof vault status."""
dummy_data = {
"initialized": True,
"sealed": False,
"authenticated": True,
"config": {
"stationID": "4c0e4a1a-795b",
"stationName": "Test FLAME Node Central",
}
}
return dummy_data
# @hub_router.get("/hub/images", response_model=ImageDataResponse)
# async def get_images():
# """Return list of images for the frontend."""
# # TODO: replace with data from https://api.privateaim.net/master-images
#
# dummy_data = {
# "pullImages": [
# {
# "id": "59081687-3dfe-46cf-afb5-07c562a002af",
# "train_class_id": "choochoo",
# "repo_tag": "0.5.23-pull",
# "job_id": "49e79b47-686b-4fb8-9259-fd0035b0b7f6",
# "status": "pulled"
# }
# ],
# "pushImages": [
# {
# "id": "4a941577-46ce-4220-8ca0-181cf45abe29",
# "train_class_id": "choochoo",
# "repo_tag": "latest",
# "job_id": "5efabb71-ba5d-4d00-9ed4-f27eb6a52e8f",
# "status": "waiting_to_push"
# }
# ],
# }
# return dummy_data
#
#
# @hub_router.get("/hub/vault/status")
# async def get_vault_status():
# """Spoof vault status."""
# dummy_data = {
# "initialized": True,
# "sealed": False,
# "authenticated": True,
# "config": {
# "stationID": "4c0e4a1a-795b",
# "stationName": "Test FLAME Node Central",
# }
# }
# return dummy_data


@route(
Expand Down Expand Up @@ -248,11 +248,19 @@ async def list_analyses_of_nodes(
status_code=status.HTTP_200_OK,
service_url=hub_adapter_settings.HUB_SERVICE_URL,
response_model=AnalysisNode,
query_params=["include"],
)
async def list_specific_analysis(
analysis_id: Annotated[uuid.UUID, Path(description="Analysis UUID.")],
request: Request,
response: Response,
analysis_id: Annotated[uuid.UUID, Path(description="Analysis UUID.")],
include: Annotated[
str | None,
Query(
description="Whether to include additional data for the given parameter. Can only be 'node'/'analysis'",
pattern="^((^|[,])(analysis|node))+$", # Must be "node" or "analysis" or null,
),
] = "analysis",
):
"""List project for a given UUID."""
pass
Expand All @@ -276,3 +284,74 @@ async def accept_reject_analysis_node(
):
"""Set the approval status of a analysis."""
pass


@route(
request_method=hub_router.get,
path="/registry-projects/{registry_project_id}",
status_code=status.HTTP_200_OK,
service_url=hub_adapter_settings.HUB_SERVICE_URL,
response_model=RegistryProject,
query_params=["include"],
)
async def get_registry_metadata_for_project(
request: Request,
response: Response,
include: Annotated[
str | None,
Query(
description="Whether to include additional registry data. Can only be 'registry'",
pattern="^registry$", # Must be "registry" or null,
),
] = "registry",
):
"""List registry data for a project."""
pass


def get_analysis_metadata_for_url(analysis_id: uuid.UUID = Path(description="UUID of analysis.")):
"""Get analysis metadata for a given UUID to be used in creating analysis image URL."""
analysis_url = hub_router.url_path_for("list_specific_analysis", analysis_id=analysis_id)
analysis_resp = RedirectResponse(analysis_url + "?include=analysis,node")
return analysis_resp


def get_registry_metadata_for_url(analysis_metadata: dict = Depends(get_analysis_metadata_for_url)):
"""Get registry metadata for a given UUID to be used in creating analysis image URL."""
registry_project_id = analysis_metadata["node"]["registry_project_id"]
registry_url = hub_router.url_path_for(
"get_registry_metadata_for_project",
registry_project_id=registry_project_id
)
registry_resp = RedirectResponse(
registry_url + "?include=registry&fields=+account_id,+account_name,+account_secret"
)
return registry_resp


@hub_router.get("/analysis/image/{analysis_id}", response_class=RedirectResponse)
async def get_analysis_image_url(
# analysis_id: Annotated[uuid.UUID, Path(description="UUID of analysis.")],
registry_metadata: dict = Depends(get_registry_metadata_for_url),

) -> dict:
"""Build an analysis image URL using its metadata from the Hub."""
aid = 2
# analysis_url = hub_router.url_path_for("list_specific_analysis", analysis_id=analysis_id)
# analysis_resp = RedirectResponse(analysis_url + "?include=analysis,node")

# analysis_resp = get_analysis_metadata_for_url(analysis_id)

# registry_project_id = analysis_metadata["node"]["registry_project_id"]

# registry_url = hub_router.url_path_for(
# "get_registry_metadata_for_project",
# registry_project_id=registry_project_id
# )
# registry_resp = RedirectResponse(
# registry_url + "?include=registry&fields=+account_id,+account_name,+account_secret"
# )
registry_external_name = registry_metadata["external_name"]
host = registry_metadata["registry"]["host"]

return {"image_url": f"{host}/{registry_external_name}/{aid}"}

0 comments on commit b74db09

Please sign in to comment.