Skip to content

Commit

Permalink
Merge pull request #93 from dbutenhof/horreum
Browse files Browse the repository at this point in the history
Add a Horreum passthrough API
  • Loading branch information
chentex authored May 31, 2024
2 parents 1569f9f + cfd5a06 commit 592a572
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 132 deletions.
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 @@ -30,4 +31,7 @@
router.include_router(telcoGraphs.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

0 comments on commit 592a572

Please sign in to comment.