Skip to content
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
16 changes: 4 additions & 12 deletions Babylon/commands/api/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,7 @@ def list_datasets(config: dict, keycloak_token: str, organization_id: str, works
@option("--oid", "organization_id", required=True, type=str, help="Organization ID")
@option("--wid", "workspace_id", required=True, type=str, help="Workspace ID")
@option("--did", "dataset_id", required=True, type=str, help="Dataset ID")
def delete(
config: dict, keycloak_token: str, organization_id: str, workspace_id: str, dataset_id: str
) -> CommandResponse:
def delete(config: dict, keycloak_token: str, organization_id: str, workspace_id: str, dataset_id: str) -> CommandResponse:
"""Delete a dataset by ID"""
api_instance = get_dataset_api_instance(config, keycloak_token)
try:
Expand All @@ -121,9 +119,7 @@ def get(config: dict, keycloak_token: str, organization_id: str, workspace_id: s
api_instance = get_dataset_api_instance(config, keycloak_token)
try:
logger.info(API_REQUEST_MESSAGE)
dataset = api_instance.get_dataset(
organization_id=organization_id, workspace_id=workspace_id, dataset_id=dataset_id
)
dataset = api_instance.get_dataset(organization_id=organization_id, workspace_id=workspace_id, dataset_id=dataset_id)
logger.info(f" [green]✔[/green] Dataset [bold cyan]{dataset.id}[/bold cyan] retrieved successfully")
return CommandResponse.success(dataset.model_dump())
except Exception as e:
Expand Down Expand Up @@ -191,9 +187,7 @@ def create_part(
if not created:
logger.error(" [bold red]✘ API returned no data.[/bold red]")
return CommandResponse.fail()
logger.info(
f" [bold green]✔[/bold green] Dataset part [bold cyan]{created.id}[/bold cyan] successfully created"
)
logger.info(f" [bold green]✔[/bold green] Dataset part [bold cyan]{created.id}[/bold cyan] successfully created")
return CommandResponse.success(created.model_dump())
except Exception as e:
logger.error(f" [bold red]✘[/bold red] Creation Failed Reason: {e}")
Expand Down Expand Up @@ -452,9 +446,7 @@ def download_part(
@option("--oid", "organization_id", required=True, type=str, help="Organization ID")
@option("--wid", "workspace_id", required=True, type=str, help="Workspace ID")
@option("--did", "dataset_id", required=True, type=str, help="Dataset ID")
def list_parts(
config: dict, keycloak_token: str, organization_id: str, workspace_id: str, dataset_id: str
) -> CommandResponse:
def list_parts(config: dict, keycloak_token: str, organization_id: str, workspace_id: str, dataset_id: str) -> CommandResponse:
"""List dataset parts"""
api_instance = get_dataset_api_instance(config, keycloak_token)
try:
Expand Down
8 changes: 2 additions & 6 deletions Babylon/commands/api/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ def create(config: dict, keycloak_token: str, payload_file) -> CommandResponse:
logger.error(" [bold red]✘[/bold red] API returned no data.")
return CommandResponse.fail()

logger.info(
f" [bold green]✔[/bold green] Organization [bold cyan]{organization.id}[/bold cyan] successfully created"
)
logger.info(f" [bold green]✔[/bold green] Organization [bold cyan]{organization.id}[/bold cyan] successfully created")
return CommandResponse.success(organization.model_dump())
except Exception as e:
logger.error(f" [bold red]✘[/bold red] Creation Failed Reason: {e}")
Expand All @@ -72,9 +70,7 @@ def delete(config: dict, keycloak_token: str, organization_id: str) -> CommandRe
# API Execution
logger.info(API_REQUEST_MESSAGE)
api_instance.delete_organization(organization_id)
logger.info(
f" [bold green]✔[/bold green] Organization [bold red]{organization_id}[/bold red] successfully deleted"
)
logger.info(f" [bold green]✔[/bold green] Organization [bold red]{organization_id}[/bold red] successfully deleted")
return CommandResponse.success()
except Exception as e:
logger.error(f" [bold red]✘[/bold red] Deletion Failed Reason: {e}")
Expand Down
12 changes: 3 additions & 9 deletions Babylon/commands/api/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ def runs():
@option("--wid", "workspace_id", required=True, type=str, help="Workspace ID")
@option("--rid", "runner_id", required=True, type=str, help="Runner ID")
@option("--rnid", "run_id", required=True, type=str, help="Run ID")
def get(
config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str, run_id: str
) -> CommandResponse:
def get(config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str, run_id: str) -> CommandResponse:
"""Get a run"""
api_instance = get_run_api_instance(config, keycloak_token)
try:
Expand All @@ -59,9 +57,7 @@ def get(
@option("--wid", "workspace_id", required=True, type=str, help="Workspace ID")
@option("--rid", "runner_id", required=True, type=str, help="Runner ID")
@option("--rnid", "run_id", required=True, type=str, help="Run ID")
def delete(
config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str, run_id: str
) -> CommandResponse:
def delete(config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str, run_id: str) -> CommandResponse:
"""Delete a run"""
api_instance = get_run_api_instance(config, keycloak_token)
try:
Expand All @@ -86,9 +82,7 @@ def delete(
@option("--oid", "organization_id", required=True, type=str, help="Organization ID")
@option("--wid", "workspace_id", required=True, type=str, help="Workspace ID")
@option("--rid", "runner_id", required=True, type=str, help="Runner ID")
def list_runs(
config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str
) -> CommandResponse:
def list_runs(config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str) -> CommandResponse:
"""List runs"""
api_instance = get_run_api_instance(config, keycloak_token)
try:
Expand Down
12 changes: 3 additions & 9 deletions Babylon/commands/api/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ def create(
@option("--oid", "organization_id", required=True, type=str, help="Organization ID")
@option("--wid", "workspace_id", required=True, type=str, help="Workspace ID")
@option("--rid", "runner_id", required=True, type=str, help="Runner ID")
def delete(
config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str
) -> CommandResponse:
def delete(config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str) -> CommandResponse:
"""Delete a runner by ID"""
api_instance = get_runner_api_instance(config, keycloak_token)
try:
Expand Down Expand Up @@ -119,9 +117,7 @@ def get(config: dict, keycloak_token: str, organization_id: str, workspace_id: s
api_instance = get_runner_api_instance(config, keycloak_token)
try:
logger.info(API_REQUEST_MESSAGE)
runner = api_instance.get_runner(
organization_id=organization_id, workspace_id=workspace_id, runner_id=runner_id
)
runner = api_instance.get_runner(organization_id=organization_id, workspace_id=workspace_id, runner_id=runner_id)
logger.info(f" [green]✔[/green] Runner [bold cyan]{runner.id}[/bold cyan] retrieved successfully")
return CommandResponse.success(runner.model_dump())
except Exception as e:
Expand Down Expand Up @@ -167,9 +163,7 @@ def update(
@option("--oid", "organization_id", required=True, type=str, help="Organization ID")
@option("--wid", "workspace_id", required=True, type=str, help="Workspace ID")
@option("--rid", "runner_id", required=True, type=str, help="Runner ID")
def start(
config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str
) -> CommandResponse:
def start(config: dict, keycloak_token: str, organization_id: str, workspace_id: str, runner_id: str) -> CommandResponse:
"""Start a run"""
api_instance = get_runner_api_instance(config, keycloak_token)
try:
Expand Down
4 changes: 1 addition & 3 deletions Babylon/commands/api/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ def create(config: dict, keycloak_token: str, organization_id: str, solution_id:
if not workspace:
logger.error(" [bold red]✘[/bold red] API returned no data.")
return CommandResponse.fail()
logger.info(
f" [bold green]✔[/bold green] Workspace [bold cyan]{workspace.id}[/bold cyan] successfully created"
)
logger.info(f" [bold green]✔[/bold green] Workspace [bold cyan]{workspace.id}[/bold cyan] successfully created")
return CommandResponse.success(workspace.model_dump())
except Exception as e:
logger.error(f" [bold red]✘[/bold red] Creation Failed Reason: {e}")
Expand Down
12 changes: 6 additions & 6 deletions Babylon/commands/macro/apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def load_resources_from_files(files_to_deploy: list[PathlibPath]) -> tuple[list,
return (organizations, solutions, workspaces, webapps)


def deploy_objects(objects: list, object_type: str):
def deploy_objects(objects: list, object_type: str, deploy_dir: PathlibPath):
for o in objects:
content = o.get("content")
namespace = o.get("namespace")
Expand All @@ -45,7 +45,7 @@ def deploy_objects(objects: list, object_type: str):
elif object_type == "solution":
deploy_solution(namespace=namespace, file_content=content)
elif object_type == "workspace":
deploy_workspace(namespace=namespace, file_content=content)
deploy_workspace(namespace=namespace, file_content=content, deploy_dir=deploy_dir)
elif object_type == "webapp":
deploy_webapp(namespace=namespace, file_content=content)

Expand Down Expand Up @@ -91,13 +91,13 @@ def apply(
env.set_variable_files(variables_files)
organizations, solutions, workspaces, webapps = load_resources_from_files(files_to_deploy)
if organization:
deploy_objects(organizations, "organization")
deploy_objects(organizations, "organization", deploy_dir)
if solution:
deploy_objects(solutions, "solution")
deploy_objects(solutions, "solution", deploy_dir)
if workspace:
deploy_objects(workspaces, "workspace")
deploy_objects(workspaces, "workspace", deploy_dir)
if webapp:
deploy_objects(webapps, "webapp")
deploy_objects(webapps, "webapp", deploy_dir)
final_state = env.get_state_from_local()
services = final_state.get("services", {})
api_data = services.get("api", {})
Expand Down
59 changes: 32 additions & 27 deletions Babylon/commands/macro/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from cosmotech_api.models.solution_security import SolutionSecurity
from cosmotech_api.models.workspace_access_control import WorkspaceAccessControl
from cosmotech_api.models.workspace_security import WorkspaceSecurity
from kubernetes import client, config

logger = getLogger(__name__)

Expand Down Expand Up @@ -94,9 +95,7 @@ def update_default_security(
getattr(api_instance, f"update_{object_type}_default_security")(object_id, desired_security.default)
logger.info(f" [bold green]✔[/bold green] Updated [magenta]{object_type}[/magenta] default security")
except Exception as e:
logger.error(
f" [bold red]✘[/bold red] Failed to update [magenta]{object_type}[/magenta] default security: {e}"
)
logger.error(f" [bold red]✘[/bold red] Failed to update [magenta]{object_type}[/magenta] default security: {e}")


def update_object_security(
Expand All @@ -121,38 +120,21 @@ def update_object_security(
if entry.id in to_add:
try:
getattr(api_instance, f"create_{object_type}_access_control")(*object_id, entry)
logger.info(
f" [bold green]✔[/bold green] Access control"
f" for id [magenta]{entry.id}[/magenta] added successfully"
)
logger.info(f" [bold green]✔[/bold green] Access control for id [magenta]{entry.id}[/magenta] added successfully")
except Exception as e:
logger.error(
f" [bold red]✘[/bold red] Failed to add access control for id [magenta]{entry.id}[/magenta]: {e}"
)
logger.error(f" [bold red]✘[/bold red] Failed to add access control for id [magenta]{entry.id}[/magenta]: {e}")
if entry.id in to_update:
try:
getattr(api_instance, f"update_{object_type}_access_control")(
*object_id, entry.id, {"role": entry.role}
)
logger.info(
f" [bold green]✔[/bold green] Access control"
f" for id [magenta]{entry.id}[/magenta] updated successfully"
)
getattr(api_instance, f"update_{object_type}_access_control")(*object_id, entry.id, {"role": entry.role})
logger.info(f" [bold green]✔[/bold green] Access control for id [magenta]{entry.id}[/magenta] updated successfully")
except Exception as e:
logger.error(
f" [bold red]✘[/bold red] Failed to update access control"
f" for id [magenta]{entry.id}[/magenta]: {e}"
)
logger.error(f" [bold red]✘[/bold red] Failed to update access control for id [magenta]{entry.id}[/magenta]: {e}")
for entry_id in to_delete:
try:
getattr(api_instance, f"delete_{object_type}_access_control")(*object_id, entry_id)
logger.info(
f" [bold green]✔[/bold green] Access control for id [magenta]{entry_id}[/magenta] deleted successfully"
)
logger.info(f" [bold green]✔[/bold green] Access control for id [magenta]{entry_id}[/magenta] deleted successfully")
except Exception as e:
logger.error(
f" [bold red]✘[/bold red] Failed to delete access control for id [magenta]{entry_id}[/magenta]: {e}"
)
logger.error(f" [bold red]✘[/bold red] Failed to delete access control for id [magenta]{entry_id}[/magenta]: {e}")


def dict_to_tfvars(payload: dict) -> str:
Expand Down Expand Up @@ -181,3 +163,26 @@ def dict_to_tfvars(payload: dict) -> str:
else:
lines.append(f'{key} = "{value}"')
return "\n".join(lines)


def get_postgres_service_host(namespace: str) -> str:
"""Discovers the PostgreSQL service name in a namespace to build its FQDN

Note: This function assumes PostgreSQL is running within the same Kubernetes cluster.
External database clusters are not currently supported.
"""
try:
config.load_kube_config()
v1 = client.CoreV1Api()
services = v1.list_namespaced_service(namespace)

for svc in services.items:
if "postgresql" in svc.metadata.name or svc.metadata.labels.get("app.kubernetes.io/name") == "postgresql":
logger.info(f" [dim]→ Found PostgreSQL service {svc.metadata.name}[/dim]")
return f"{svc.metadata.name}.{namespace}.svc.cluster.local"

return f"postgresql.{namespace}.svc.cluster.local"
except Exception as e:
logger.warning(" [bold yellow]⚠[/bold yellow] Service discovery failed ! default will be used.")
logger.debug(f" Exception details: {e}", exc_info=True)
return f"postgresql.{namespace}.svc.cluster.local"
13 changes: 3 additions & 10 deletions Babylon/commands/macro/deploy_organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ def deploy_organization(namespace: str, file_content: str):
state["services"]["api"]["organization_id"] = organization.id
else:
# Case: Update Existing Organization
logger.info(
f" [dim]→ Existing ID [bold cyan]{api_section['organization_id']}[/bold cyan] found. Updating...[/dim]"
)
logger.info(f" [dim]→ Existing ID [bold cyan]{api_section['organization_id']}[/bold cyan] found. Updating...[/dim]")
organization_update_request = OrganizationUpdateRequest.from_dict(payload)
updated = api_instance.update_organization(
organization_id=api_section["organization_id"], organization_update_request=organization_update_request
Expand All @@ -63,9 +61,7 @@ def deploy_organization(namespace: str, file_content: str):
if payload.get("security"):
try:
logger.info(" [dim]→ Syncing security policies...[/dim]")
current_security = api_instance.get_organization_security(
organization_id=api_section["organization_id"]
)
current_security = api_instance.get_organization_security(organization_id=api_section["organization_id"])
update_object_security(
"organization",
current_security=current_security,
Expand All @@ -76,10 +72,7 @@ def deploy_organization(namespace: str, file_content: str):
except Exception as e:
logger.error(f" [bold red]✘[/bold red] Security update failed: {e}")
return CommandResponse.fail()
logger.info(
f" [bold green]✔[/bold green] Organization"
f" [bold magenta]{api_section['organization_id']}[/bold magenta] updated"
)
logger.info(f" [bold green]✔[/bold green] Organization [bold magenta]{api_section['organization_id']}[/bold magenta] updated")
# --- State Persistence ---
# Ensure the local and remote states are synchronized after successful API calls
env.store_state_in_local(state)
Expand Down
8 changes: 2 additions & 6 deletions Babylon/commands/macro/deploy_solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ def deploy_solution(namespace: str, file_content: str) -> bool:
state["services"]["api"]["solution_id"] = solution.id
else:
# Case: Update Existing Solution
logger.info(
f" [dim]→ Existing ID [bold cyan]{api_section['solution_id']}[/bold cyan] found. Updating...[/dim]"
)
logger.info(f" [dim]→ Existing ID [bold cyan]{api_section['solution_id']}[/bold cyan] found. Updating...[/dim]")
solution_update_request = SolutionUpdateRequest.from_dict(payload)
updated = api_instance.update_solution(
organization_id=api_section["organization_id"],
Expand All @@ -80,9 +78,7 @@ def deploy_solution(namespace: str, file_content: str) -> bool:
except Exception as e:
logger.error(f" [bold red]✘[/bold red] Security update failed: {e}")
return CommandResponse.fail()
logger.info(
f" [bold green]✔[/bold green] Solution [bold magenta]{api_section['solution_id']}[/bold magenta] updated"
)
logger.info(f" [bold green]✔[/bold green] Solution [bold magenta]{api_section['solution_id']}[/bold magenta] updated")
# --- State Persistence ---
# Ensure the local and remote states are synchronized after successful API calls
env.store_state_in_local(state)
Expand Down
8 changes: 2 additions & 6 deletions Babylon/commands/macro/deploy_webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ def deploy_webapp(namespace: str, file_content: str):
return
logger.info(" [dim]→ Running Terraform deployment...[/dim]")
try:
process = subprocess.Popen(
executable, cwd=tf_dir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1
)
process = subprocess.Popen(executable, cwd=tf_dir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1)
for line in process.stdout:
clean_line = line.strip()
if not clean_line:
Expand All @@ -74,9 +72,7 @@ def deploy_webapp(namespace: str, file_content: str):
services["webapp"]["webapp_name"] = f"webapp-{webapp_name}"
services["webapp"]["webapp_url"] = webapp_url
if return_code == 0:
logger.info(
f" [bold green]✔[/bold green] WebApp [bold white]{webapp_name}[/bold white] deployed successfully"
)
logger.info(f" [bold green]✔[/bold green] WebApp [bold white]{webapp_name}[/bold white] deployed successfully")
env.store_state_in_local(state)
if env.remote:
env.store_state_in_cloud(state)
Expand Down
Loading