Skip to content

Commit

Permalink
feat(api): Add key/value store with namespace emulation
Browse files Browse the repository at this point in the history
For storing pipeline settings and variable and make them
a bit more stateful we need reliable key/value store.

Signed-off-by: Denys Fedoryshchenko <[email protected]>
  • Loading branch information
nuclearcat committed Oct 25, 2024
1 parent d1b28bd commit c1ac35f
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
19 changes: 19 additions & 0 deletions api/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from motor import motor_asyncio
from kernelci.api.models import Hierarchy, Node, parse_node_obj

Check failure on line 13 in api/db.py

View workflow job for this annotation

GitHub Actions / Lint

Unable to import 'kernelci.api.models'
from .models import User, UserGroup
from redis import asyncio as aioredis

Check warning on line 15 in api/db.py

View workflow job for this annotation

GitHub Actions / Lint

third party import "from redis import asyncio as aioredis" should be placed before "from .models import User, UserGroup"


class Database:
Expand Down Expand Up @@ -44,6 +45,8 @@ class Database:

def __init__(self, service='mongodb://db:27017', db_name='kernelci'):
self._motor = motor_asyncio.AsyncIOMotorClient(service)
# TBD: Make redis host configurable
self._redis = aioredis.from_url('redis://redis:6379')
self._db = self._motor[db_name]

async def initialize_beanie(self):
Expand All @@ -59,6 +62,22 @@ def _get_collection(self, model):
col = self.COLLECTIONS[model]
return self._db[col]

def get_kv(self, namespace, key):

Check warning on line 65 in api/db.py

View workflow job for this annotation

GitHub Actions / Lint

Missing function or method docstring
keyname = f"{namespace}:{key}"
return self._redis.get(keyname)

def set_kv(self, namespace, key, value):

Check warning on line 69 in api/db.py

View workflow job for this annotation

GitHub Actions / Lint

Missing function or method docstring
keyname = f"{namespace}:{key}"
return self._redis.set(keyname, value)

def del_kv(self, namespace, key):

Check warning on line 73 in api/db.py

View workflow job for this annotation

GitHub Actions / Lint

Missing function or method docstring
keyname = f"{namespace}:{key}"
return self._redis.delete(keyname)

def exists_kv(self, namespace, key):

Check warning on line 77 in api/db.py

View workflow job for this annotation

GitHub Actions / Lint

Missing function or method docstring
keyname = f"{namespace}:{key}"
return self._redis.exists(keyname)

async def create_indexes(self):
"""Create indexes for models"""
for model in self.COLLECTIONS:
Expand Down
44 changes: 43 additions & 1 deletion api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
Request,
Form,
Header,
Query
Query,
Body,
)
from fastapi.responses import JSONResponse, PlainTextResponse, FileResponse
from fastapi.security import OAuth2PasswordRequestForm
Expand Down Expand Up @@ -738,6 +739,47 @@ async def put_nodes(
return obj_list


# -----------------------------------------------------------------------------
# Key/Value namespace enabled store
@app.get('/kv/{namespace}/{key}', response_model=Union[str, None])
async def get_kv(namespace: str, key: str,
user: User = Depends(get_current_user)):

"""Get a key value pair from the store"""
metrics.add('http_requests_total', 1)
return await db.get_kv(namespace, key)


@app.post('/kv/{namespace}/{key}', response_model=Optional[str])
async def post_kv(namespace: str, key: str,
value: str = Body(...),
user: User = Depends(get_current_user)):
"""Set a key-value pair in the store
namespace and key are part of the URL
value is part of the request body
"""
metrics.add('http_requests_total', 1)
ret = await db.set_kv(namespace, key, value)
if ret:
return "OK"
raise HTTPException(status_code=500, detail="Failed to set key-value pair")


# Delete a key-value pair from the store
@app.delete('/kv/{namespace}/{key}', response_model=Optional[str])
async def delete_kv(namespace: str, key: str,
user: User = Depends(get_current_user)):
"""Delete a key-value pair from the store"""
metrics.add('http_requests_total', 1)
# Check if the key exists in the namespace before deletion
if not await db.exists_kv(namespace, key):
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail=f"Key '{namespace}:{key}' not found")
await db.delete_kv(namespace, key)

Check failure on line 778 in api/main.py

View workflow job for this annotation

GitHub Actions / Lint

Instance of 'Database' has no 'delete_kv' member
response = "Key-value pair deleted successfully"
return response


# -----------------------------------------------------------------------------
# Pub/Sub

Expand Down

0 comments on commit c1ac35f

Please sign in to comment.