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

Add a Horreum passthrough API #93

Merged
merged 2 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ port=8000
url=
personal_access_token=

[horreum]
url=
username=
password=

[airflow]
url=
username=
Expand Down Expand Up @@ -62,14 +67,31 @@ password=

Internally the API when serving the `/ocp` enpoints will use this connection. Also it is suggested to create indexes with same name in the archived instances too to avoid further complications.

The `jira` table requires a `url` key and a `personal_access_token` key. The `url` is a string value that points to the URL address of your Jira resource. The [Personal Access Token](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) is a string value that is the credential issued to authenticate and authorize this application with your Jira resource.
The `jira` configuration requires a `url` key and a `personal_access_token` key. The `url` is a string value that points to the URL address of your Jira resource. The [Personal Access Token](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) is a string value that is the credential issued to authenticate and authorize this application with your Jira resource.

```toml
[jira]
url=""
personal_access_token=""
```

The `horreum` configuration requires the `url` of a running Horreum server,
along with the `username` and `password` to be used to authenticate Horreum
queries.

All `GET` calls to `/api/v1/horreum/api/{path}` will be passed through to
Horreum, including query parameters, and Horreum's response will be returned
to the caller. For example, `GET /api/v1/horreum/api/test/{id}` will return the
same response as directly calling `GET {horreum.url}/api/test/{id}` with the
configured Horreum credentials.

```toml
[horreum]
url="http://localhost:8080"
username="user"
password="secret"
```


## Development on System

Expand Down
2 changes: 1 addition & 1 deletion backend/app/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#
#
6 changes: 5 additions & 1 deletion backend/app/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from app.api.v1.endpoints.ocp import graph
from app.api.v1.endpoints.cpt import cptJobs
from app.api.v1.endpoints.jira import jira
from app.api.v1.endpoints.horreum import horreum
from app.api.v1.endpoints.quay import quayJobs
from app.api.v1.endpoints.quay import quayGraphs
from app.api.v1.endpoints.telco import telcoJobs
Expand All @@ -27,4 +28,7 @@
router.include_router(telcoJobs.router, tags=['telco'])

# Jira endpoints
router.include_router(jira.router, tags=['jira'])
router.include_router(jira.router, tags=['jira'])

# Horreum endpoint
router.include_router(horreum.router, tags=['horreum'])
32 changes: 32 additions & 0 deletions backend/app/api/v1/endpoints/horreum/horreum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from http import HTTPStatus
from typing import Annotated, Any

from fastapi.responses import JSONResponse

from app.services.horreum_svc import HorreumService
from fastapi import APIRouter, Path, Request, Response

router = APIRouter()


@router.get("/api/v1/horreum/api/{path:path}")
async def horreum(
request: Request, path: Annotated[str, Path(title="Horreum API path")]
) -> Response:
"""Pass GET API call to Horreum

Makes an authenticated Horreum call using the configured Horreum URL,
username, and password. It passes on the query parameters as well as the
Horreum API path, and returns the status, content, and response headers
to the caller.

Args:
request: Tells FastAPI to show us the full request object
path: A Horreum API path, like /api/test/byName/name
"""
response = HorreumService("horreum").get(path, dict(request.query_params.items()))
return Response(
status_code=response.status_code,
headers=response.headers,
content=response.content,
)
39 changes: 39 additions & 0 deletions backend/app/services/horreum_svc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import sys
from typing import Optional

import requests
from app import config
from keycloak.keycloak_openid import KeycloakOpenID


class HorreumService:

def __init__(self, configpath="horreum"):
self.cfg = config.get_config()
self.user = self.cfg.get(configpath + ".username")
self.password = self.cfg.get(configpath + ".password")
self.url = self.cfg.get(configpath + ".url")
try:
kc = requests.get(f"{self.url}/api/config/keycloak")
kc.raise_for_status()
except Exception as e:
print(f"Failed {str(e)!r}", file=sys.stderr)
raise
keycloak = kc.json()
self.keycloak = KeycloakOpenID(
keycloak["url"],
client_id=keycloak["clientId"],
realm_name=keycloak["realm"],
)

def get(
self, path: str, queries: Optional[dict[str, str]] = None
) -> requests.Response:
token = self.keycloak.token(username=self.user, password=self.password)[
"access_token"
]
return requests.get(
f"{self.url}/api/{path}",
params=queries,
headers={"authorization": f"Bearer {token}"},
)
2 changes: 0 additions & 2 deletions backend/backend.containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,3 @@ RUN pip install --user poetry && \
pip install --no-cache-dir -r requirements.txt

ENTRYPOINT ["/bin/bash", "./scripts/start.sh"]


Loading
Loading