Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@

import urllib

from core.models import AppDeploymentRequest
from core.constants import TERRAFORM_DIRECTORY, TEMPLATE_DIRECTORY, GENERATED_CONFIGS_DIR
from core import utils
from ..core.models import AppDeploymentRequest
from ..core.constants import TERRAFORM_DIRECTORY, TEMPLATE_DIRECTORY, GENERATED_CONFIGS_DIR
from ..core import utils

logger = logging.getLogger(__name__)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
import logging
import os

from core.models import InfraDeploymentRequest
from core.utils import render_jinja_template, write_file_content
from core.constants import TERRAFORM_DIRECTORY, TEMPLATE_DIRECTORY
from ..core.models import InfraDeploymentRequest
from ..core.utils import render_jinja_template, write_file_content
from ..core.constants import TERRAFORM_DIRECTORY, TEMPLATE_DIRECTORY

logger = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion onix/deploy/onix-installer/backend/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from jinja2 import Environment, FileSystemLoader, TemplateNotFound
import yaml

from core.constants import ANSI_ESCAPE_PATTERN
from .constants import ANSI_ESCAPE_PATTERN

logger = logging.getLogger(__name__)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ cleanup() {
echo "Stopping frontend server (ng serve)..."
pkill -f "ng serve" || echo "Frontend server was not running."
echo "Stopping backend server (uvicorn)..."
pkill -f "uvicorn main:app" || echo "Backend server was not running."
pkill -f "uvicorn backend.main:app" || echo "Backend server was not running."
else
echo "pkill not found, falling back to lsof to find processes by port."
echo "Stopping frontend server (on port 4200)..."
Expand Down Expand Up @@ -258,7 +258,7 @@ if [ -d "$BACKEND_DIR" ] && [ -f "$BACKEND_DIR/main.py" ]; then

echo "🔵 Starting backend server..."
echo "View logs at $LOG_DIR/backend.log"
uvicorn main:app --reload > "$LOG_DIR/backend.log" 2>&1 &
PYTHONPATH=.. uvicorn backend.main:app --reload > "$LOG_DIR/backend.log" 2>&1 &

# Store the PID of uvicorn for potential future use in cleanup if needed
# (though pkill -f is generally sufficient)
Expand Down
73 changes: 48 additions & 25 deletions onix/deploy/onix-installer/backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Main FastAPI application for the Onix Installer backend.

This module sets up the FastAPI server, middleware, and defines all
API endpoints, including REST endpoints for GCP resource management
and WebSocket endpoints for long-running deployment processes.
"""

import json
import logging
import sys
Expand All @@ -21,11 +29,11 @@
from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware

from core.models import InfraDeploymentRequest, AppDeploymentRequest, ProxyRequest
from services.gcp_resource_manager import list_google_cloud_projects, list_google_cloud_regions
from services.deployment_manager import run_infra_deployment, run_app_deployment
from services import ui_state_manager as ui_state
from services.health_checks import run_websocket_health_check
from .core.models import InfraDeploymentRequest, AppDeploymentRequest, ProxyRequest
from .services.gcp_resource_manager import list_google_cloud_projects, list_google_cloud_regions
from .services.deployment_manager import run_infra_deployment, run_app_deployment
from .services import ui_state_manager as ui_state
from .services.health_checks import run_websocket_health_check

logging.basicConfig(level=logging.DEBUG,
format='%(name)s - %(levelname)s - %(message)s',
Expand All @@ -46,6 +54,9 @@

@app.get("/root")
def read_root():
"""
Root endpoint to check if the server is running.
"""
logger.info("Root endpoint accessed.")
return {"message": "FastAPI deployment server is running"}

Expand All @@ -58,17 +69,17 @@ async def get_projects():
logger.info("Attempting to list Google Cloud projects.")
try:
projects = await list_google_cloud_projects()
logger.info(f"Successfully retrieved {len(projects)} Google Cloud projects.")
logger.info("Successfully retrieved %s Google Cloud projects.", len(projects))
return projects
except HTTPException as e:
logger.error(f"Failed to list GCP projects: {e.detail}")
logger.error("Failed to list GCP projects: %s", e.detail)
raise e
except Exception as e:
logger.exception("An unexpected error occurred while listing GCP projects.")
raise HTTPException(
status_code=500,
detail=f"An unexpected internal server error occurred: {e}"
)
) from e

@app.get("/regions", response_model=list[str])
async def get_regions():
Expand All @@ -78,26 +89,30 @@ async def get_regions():
logger.info("Attempting to list Google Cloud regions.")
try:
regions = await list_google_cloud_regions()
logger.info(f"Successfully retrieved {len(regions)} Google Cloud regions.")
logger.info("Successfully retrieved %s Google Cloud regions.", len(regions))
return regions
except HTTPException as e:
logger.error(f"Failed to list GCP regions: {e.detail}")
logger.error("Failed to list GCP regions: %s", e.detail)
raise e
except Exception as e:
logger.exception("An unexpected error occurred while listing GCP regions.")
raise HTTPException(
status_code=500,
detail=f"An unexpected internal server error occurred: {e}"
)
) from e

@app.websocket("/ws/deployInfra")
async def websocket_deploy_infra(websocket: WebSocket):
"""
WebSocket endpoint to handle infrastructure (Terraform) deployments.
Receives deployment configuration, streams logs, and sends final status.
"""
await websocket.accept()
logger.info("WebSocket connection established for /ws/deployInfra.")
try:
data = await websocket.receive_json()
config = InfraDeploymentRequest(**data)
logger.info(f"Received infrastructure deployment request with payload: {config}.")
logger.info("Received infrastructure deployment request with payload: %s.", config)

await run_infra_deployment(config, websocket)

Expand All @@ -119,13 +134,17 @@ async def websocket_deploy_infra(websocket: WebSocket):

@app.websocket("/ws/deployApp")
async def websocket_deploy_application(websocket: WebSocket):
"""
WebSocket endpoint to handle application (K8s/Helm) deployments.
Receives deployment configuration, streams logs, and sends final status.
"""
await websocket.accept()
logger.info("WebSocket connection established for /ws/deployApp.")

try:
app_request_payload = await websocket.receive_json()
app_deployment_request = AppDeploymentRequest(**app_request_payload)
logger.info(f"Received application deployment request with payload: {app_deployment_request}")
logger.info("Received application deployment request with payload: %s", app_deployment_request)

await run_app_deployment(app_deployment_request, websocket)

Expand All @@ -147,11 +166,15 @@ async def websocket_deploy_application(websocket: WebSocket):

@app.websocket("/ws/healthCheck")
async def websocket_health_check(websocket: WebSocket):
"""
WebSocket endpoint to run health checks on deployed services.
Receives a dictionary of service URLs and streams back their status.
"""
await websocket.accept()
logger.info("WebSocket connection established for /ws/healthCheck.")
try:
service_urls_to_check: Dict[str, str] = await websocket.receive_json()
logger.info(f"Received health check request for services: {list(service_urls_to_check.keys())}.")
logger.info("Received health check request for services: %s.", list(service_urls_to_check.keys()))
await run_websocket_health_check(websocket, service_urls_to_check)
except WebSocketDisconnect:
logger.info("Client disconnected from /ws/healthCheck.")
Expand Down Expand Up @@ -182,17 +205,18 @@ def store_or_update_values(items: Dict[str, Any]) -> Dict[str, Any]:
Returns:
Dict[str, Any]: A confirmation message along with the data that was processed.
"""
logger.info(f"Received request for bulk store/update of data. Keys: {list(items.keys())}")
logger.info("Received request for bulk store/update of data. Keys: %s", list(items.keys()))
try:
ui_state.store_bulk_values(items)
logger.info(f"Successfully stored/updated bulk data for keys: {list(items.keys())}")
logger.info("Successfully stored/updated bulk data for keys: %s", list(items.keys()))
return {
"message": "Data stored or updated successfully",
"processed_data": items
}
except Exception as e:
logger.error(f"Failed to perform bulk store/update for keys {list(items.keys())}: {e}")
raise HTTPException(status_code=500, detail=f"Failed to store bulk data: {e}")
logger.error("Failed to perform bulk store/update for keys %s: %s", list(items.keys()), e)
raise HTTPException(status_code=500,
detail=f"Failed to store bulk data: {e}") from e


@app.get("/store")
Expand All @@ -208,8 +232,8 @@ def get_all_stored_data() -> Dict[str, Any]:
logger.info("Successfully retrieved all stored data.")
return data_store
except Exception as e:
logger.error(f"Failed to retrieve all stored data: {e}")
raise HTTPException(status_code=500, detail=f"Failed to retrieve data: {e}")
logger.error("Failed to retrieve all stored data: %s", e)
raise HTTPException(status_code=500, detail=f"Failed to retrieve data: {e}") from e


@app.post("/api/dynamic-proxy")
Expand All @@ -224,7 +248,7 @@ async def dynamic_proxy(request: ProxyRequest) -> Any:
target_url = request.targetUrl
payload = request.payload

logger.info(f"Forwarding request to: {target_url}")
logger.info("Forwarding request to: %s", target_url)

async with httpx.AsyncClient() as client:
try:
Expand All @@ -233,15 +257,14 @@ async def dynamic_proxy(request: ProxyRequest) -> Any:
# todo : send response.status_code as well
return response.content
except httpx.HTTPStatusError as exc:
logger.error(f"HTTP error occurred: {exc.response.status_code} - {exc.response.text}")
logger.error("HTTP error occurred: %s - %s", exc.response.status_code, exc.response.text)
raise HTTPException(
status_code=exc.response.status_code,
detail=exc.response.text
)
except Exception as e:
logger.error(f"An unexpected error occurred: {e}")
logger.error("An unexpected error occurred: %s", e)
raise HTTPException(
status_code=500,
detail="An internal server error occurred."
)

) from e
Loading
Loading