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

[Feature] dev-mode (app hooks) #1976

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
11 changes: 11 additions & 0 deletions agenta-backend/agenta_backend/models/api/api_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class UpdateVariantParameterPayload(BaseModel):
parameters: Dict[str, Any]


class UpdateVariantURL(BaseModel):
url: str


class AppVariant(BaseModel):
app_id: str
app_name: str
Expand Down Expand Up @@ -183,6 +187,13 @@ class AddVariantFromImagePayload(BaseModel):
config_name: Optional[str]


class AddVariantFromURLPayload(BaseModel):
app_name: str
variant_slug: str
variant_name: str
url: str


class ImageExtended(Image):
# includes the mongodb image id
id: str
Expand Down
52 changes: 52 additions & 0 deletions agenta-backend/agenta_backend/routers/app_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
App,
CreateAppOutput,
AddVariantFromImagePayload,
AddVariantFromURLPayload,
)

if isCloudEE():
Expand Down Expand Up @@ -393,6 +394,57 @@ async def add_variant_from_image(
raise HTTPException(status_code=500, detail=str(e))


@router.post("/{app_id}/variant/from-url/", operation_id="add_variant_from_url")
async def add_variant_from_url(
app_id: str,
payload: AddVariantFromURLPayload,
request: Request,
):
"""
...
"""

try:
app = await db_manager.fetch_app_by_id(app_id)

if isCloudEE():
has_permission = await check_action_access(
user_uid=request.state.user_id,
object=app,
permission=Permission.CREATE_APPLICATION,
)
logger.debug(
f"User has Permission to create app from url: {has_permission}"
)
if not has_permission:
error_msg = f"You do not have access to perform this action. Please contact your organization admin."
return JSONResponse(
{"detail": error_msg},
status_code=403,
)

variant_db = await app_manager.add_variant_based_on_url(
app=app,
app_name=payload.app_name,
variant_slug=payload.variant_slug,
variant_name=payload.variant_name,
url=payload.url,
user_uid=request.state.user_id,
)

app_variant_db = await db_manager.fetch_app_variant_by_id(str(variant_db.id))

await evaluator_manager.create_ready_to_use_evaluators(app=app)

app_variant_dto = await converters.app_variant_db_to_output(app_variant_db)

return app_variant_dto

except Exception as e:
logger.exception(f"An error occurred: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))


@router.delete("/{app_id}/", operation_id="remove_app")
async def remove_app(app_id: str, request: Request):
"""Remove app, all its variant, containers and images
Expand Down
57 changes: 57 additions & 0 deletions agenta-backend/agenta_backend/routers/variants_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
AppVariantRevision,
AddVariantFromBasePayload,
UpdateVariantParameterPayload,
UpdateVariantURL,
)

router = APIRouter()
Expand Down Expand Up @@ -273,6 +274,62 @@ async def update_variant_image(
raise HTTPException(status_code=500, detail=detail)


@router.put("/{variant_id}/url/", operation_id="update_variant_url")
async def update_variant_url(
variant_id: str,
payload: UpdateVariantURL,
request: Request,
):
"""
...
"""

try:
db_app_variant = await db_manager.fetch_app_variant_by_id(
app_variant_id=variant_id
)

if isCloudEE():
has_permission = await check_action_access(
user_uid=request.state.user_id,
object=db_app_variant,
permission=Permission.CREATE_APPLICATION,
)
logger.debug(
f"User has Permission to update variant image: {has_permission}"
)
if not has_permission:
error_msg = f"You do not have permission to perform this action. Please contact your organization admin."
logger.error(error_msg)
return JSONResponse(
{"detail": error_msg},
status_code=403,
)

await app_manager.update_variant_url(
db_app_variant, payload.url, request.state.user_id
)

except ValueError as e:
import traceback

traceback.print_exc()
detail = f"Error while trying to update the app variant: {str(e)}"
raise HTTPException(status_code=500, detail=detail)
except DockerException as e:
import traceback

traceback.print_exc()
detail = f"Docker error while trying to update the app variant: {str(e)}"
raise HTTPException(status_code=500, detail=detail)
except Exception as e:
import traceback

traceback.print_exc()
detail = f"Unexpected error while trying to update the app variant: {str(e)}"
raise HTTPException(status_code=500, detail=detail)


@router.put("/{variant_id}/", operation_id="start_variant")
async def start_variant(
request: Request,
Expand Down
130 changes: 130 additions & 0 deletions agenta-backend/agenta_backend/services/app_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,44 @@ async def update_variant_image(
await start_variant(app_variant_db)


async def update_variant_url(app_variant_db: AppVariantDB, url: str, user_uid: str):
"""
...
"""

parsed_url = urlparse(url).geturl()

base = await db_manager.fetch_base_by_id(str(app_variant_db.base_id))

deployment = await db_manager.get_deployment_by_id(str(base.deployment_id))

await db_manager.remove_deployment(str(deployment.id))

await db_manager.update_variant_parameters(
str(app_variant_db.id), parameters={}, user_uid=user_uid
)

app_variant_db = await db_manager.update_app_variant(
app_variant_id=str(app_variant_db.id), url=parsed_url
)

deployment = await db_manager.create_deployment(
app_id=str(app_variant_db.app.id),
user_id=str(app_variant_db.user.id),
uri=parsed_url,
status="running",
organization=str(app_variant_db.organization_id) if isCloudEE() else None,
workspace=str(app_variant_db.workspace_id) if isCloudEE() else None,
)

await db_manager.update_base(
str(app_variant_db.base_id),
deployment_id=deployment.id,
)

return URI(uri=deployment.uri)


async def terminate_and_remove_app_variant(
app_variant_id: Optional[str] = None, app_variant_db: Optional[AppVariantDB] = None
) -> None:
Expand Down Expand Up @@ -498,3 +536,95 @@ async def add_variant_based_on_image(
)
logger.debug("End: Successfully created db_app_variant: %s", db_app_variant)
return db_app_variant


async def add_variant_based_on_url(
app: AppDB,
app_name: str,
variant_slug: str,
variant_name: str,
url: str,
user_uid: str,
) -> AppVariantDB:
"""
...
"""

logger.debug("Start: Creating app variant based on url")

logger.debug("Validating input parameters")
if (
app in [None, ""]
or app_name in [None, ""]
or variant_slug in [None, ""]
or variant_name in [None, ""]
or url in [None, ""]
):
raise ValueError("App variant, app name, variant name, or URL is None")

logger.debug("Parsing URL")
parsed_url = urlparse(url).geturl()

logger.debug("Checking if app variant already exists")
variants = await db_manager.list_app_variants_for_app_id(app_id=str(app.id))

already_exists = any(av for av in variants if av.variant_name == variant_name) # type: ignore
if already_exists:
logger.error("App variant with the same name already exists")
raise ValueError("App variant with the same name already exists")

logger.debug("Retrieving user and image objects")
user_instance = await db_manager.get_user(user_uid)

# Create config
logger.debug("Creating config")
config_db = await db_manager.create_new_config(
config_name=variant_slug, parameters={}
)

# Create base
logger.debug("Creating app")
db_base = await db_manager.create_new_variant_base(
app=app,
user=user_instance,
base_name=app_name,
organization=str(app.organization_id) if isCloudEE() else None, # noqa
workspace=str(app.workspace_id) if isCloudEE() else None, # noqa
)

# Create app variant
logger.debug("Creating app variant")
db_app_variant = await db_manager.create_new_app_variant(
app=app,
base_name=app_name,
variant_name=variant_name,
config=config_db,
base=db_base,
user=user_instance,
organization=str(app.organization_id) if isCloudEE() else None, # noqa
workspace=str(app.workspace_id) if isCloudEE() else None, # noqa
)

deployment = await db_manager.create_deployment(
app_id=str(db_app_variant.app.id),
user_id=str(db_app_variant.user.id),
uri=parsed_url,
status="running",
organization=str(db_app_variant.organization_id) if isCloudEE() else None,
workspace=str(db_app_variant.workspace_id) if isCloudEE() else None,
)

await db_manager.update_base(
str(db_app_variant.base_id),
deployment_id=deployment.id,
)

await db_manager.deploy_to_environment(
environment_name="production",
variant_id=str(db_app_variant.id),
user_uid=user_uid,
)

logger.debug("End: Successfully created variant: %s", db_app_variant)

return db_app_variant
16 changes: 10 additions & 6 deletions agenta-backend/agenta_backend/services/db_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ async def create_new_variant_base(
app: AppDB,
user: UserDB,
base_name: str,
image: ImageDB,
image: Optional[ImageDB] = None,
organization=None,
workspace=None,
) -> VariantBaseDB:
Expand All @@ -371,12 +371,13 @@ async def create_new_variant_base(
"""

logger.debug(f"Creating new base: {base_name} with image: {image} for app: {app}")
# logger.debug(f"Creating new base: {base_name} for app: {app}")
async with db_engine.get_session() as session:
base = VariantBaseDB(
app_id=app.id,
user_id=user.id,
base_name=base_name,
image_id=image.id,
image_id=image.id if image is not None else None,
)

if isCloudEE():
Expand Down Expand Up @@ -419,10 +420,10 @@ async def create_new_app_variant(
app: AppDB,
user: UserDB,
variant_name: str,
image: ImageDB,
base: VariantBaseDB,
config: ConfigDB,
base_name: str,
image: Optional[ImageDB] = None,
organization=None,
workspace=None,
) -> AppVariantDB:
Expand All @@ -447,7 +448,7 @@ async def create_new_app_variant(
modified_by_id=user.id,
revision=0,
variant_name=variant_name,
image_id=image.id,
image_id=image.id if image is not None else None,
base_id=base.id,
base_name=base_name,
config_name=config.config_name,
Expand Down Expand Up @@ -571,10 +572,10 @@ async def create_image(
async def create_deployment(
app_id: str,
user_id: str,
container_name: str,
container_id: str,
uri: str,
status: str,
container_name: Optional[str] = "",
container_id: Optional[str] = "",
organization=None,
workspace=None,
) -> DeploymentDB:
Expand Down Expand Up @@ -791,6 +792,7 @@ async def get_user(user_uid: str) -> UserDB:
# 1. Check if user_uid is found in the UserDB.uid column.
# 2. If not found, check if user_uid is found in the UserDB.id column.
conditions = [UserDB.uid == user_uid]

if isCloudEE():
conditions.append(UserDB.id == uuid.UUID(user_uid))

Expand Down Expand Up @@ -1241,9 +1243,11 @@ async def deploy_to_environment(
"""

app_variant_db = await fetch_app_variant_by_id(variant_id)

app_variant_revision_db = await fetch_app_variant_revision_by_variant(
app_variant_id=variant_id, revision=app_variant_db.revision # type: ignore
)

if app_variant_db is None:
raise ValueError("App variant not found")

Expand Down
Loading
Loading