provisioning/core/nulib/api/routes.nu

366 lines
13 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env nu
# API Routes and handlers for Provisioning System
# Defines all REST API endpoints and their handlers
use ../lib_provisioning/utils/settings.nu *
use ../main_provisioning/query.nu *
# Route definitions for the API server
export def get_route_definitions []: nothing -> list {
[
{
method: "GET"
path: "/api/v1/health"
handler: "health_check"
description: "Health check endpoint"
parameters: []
}
{
method: "GET"
path: "/api/v1/query"
handler: "query_infrastructure"
description: "Query infrastructure state"
parameters: [
{ name: "target", type: "string", required: false, default: "servers", description: "Query target (servers, metrics, logs)" }
{ name: "infra", type: "string", required: false, description: "Infrastructure name" }
{ name: "provider", type: "string", required: false, description: "Provider filter" }
{ name: "find", type: "string", required: false, description: "Search filter" }
{ name: "format", type: "string", required: false, default: "json", description: "Output format" }
]
}
{
method: "POST"
path: "/api/v1/query"
handler: "complex_query"
description: "Execute complex queries with request body"
body_schema: {
type: "object"
properties: {
query_type: { type: "string", enum: ["infrastructure", "metrics", "logs", "ai"] }
target: { type: "string" }
filters: { type: "object" }
ai_query: { type: "string", description: "Natural language query" }
aggregations: { type: "array" }
}
}
}
{
method: "GET"
path: "/api/v1/metrics"
handler: "get_metrics"
description: "Retrieve system metrics"
parameters: [
{ name: "timerange", type: "string", default: "1h", description: "Time range (1m, 5m, 1h, 1d)" }
{ name: "metric_type", type: "string", description: "Metric type filter" }
{ name: "aggregation", type: "string", default: "avg", description: "Aggregation method" }
]
}
{
method: "GET"
path: "/api/v1/logs"
handler: "get_logs"
description: "Retrieve system logs"
parameters: [
{ name: "level", type: "string", default: "info", description: "Log level filter" }
{ name: "service", type: "string", description: "Service name filter" }
{ name: "since", type: "string", default: "1h", description: "Time since" }
{ name: "limit", type: "integer", default: 100, description: "Number of entries" }
]
}
{
method: "GET"
path: "/api/v1/dashboard"
handler: "get_dashboard_data"
description: "Dashboard data endpoint"
parameters: [
{ name: "view", type: "string", default: "overview", description: "Dashboard view" }
{ name: "refresh", type: "boolean", default: false, description: "Force refresh" }
]
}
{
method: "GET"
path: "/api/v1/servers"
handler: "list_servers"
description: "List all servers"
parameters: [
{ name: "status", type: "string", description: "Status filter" }
{ name: "provider", type: "string", description: "Provider filter" }
{ name: "infra", type: "string", description: "Infrastructure filter" }
]
}
{
method: "GET"
path: "/api/v1/servers/{id}"
handler: "get_server"
description: "Get specific server details"
path_params: [
{ name: "id", type: "string", required: true, description: "Server ID" }
]
}
{
method: "GET"
path: "/api/v1/servers/{id}/status"
handler: "get_server_status"
description: "Get server status and metrics"
path_params: [
{ name: "id", type: "string", required: true, description: "Server ID" }
]
}
{
method: "GET"
path: "/api/v1/servers/{id}/logs"
handler: "get_server_logs"
description: "Get server-specific logs"
path_params: [
{ name: "id", type: "string", required: true, description: "Server ID" }
]
}
{
method: "POST"
path: "/api/v1/servers"
handler: "create_server"
description: "Create new server"
body_schema: {
type: "object"
required: ["name", "provider"]
properties: {
name: { type: "string" }
provider: { type: "string" }
infra: { type: "string" }
instance_type: { type: "string" }
count: { type: "integer", default: 1 }
}
}
}
{
method: "DELETE"
path: "/api/v1/servers/{id}"
handler: "delete_server"
description: "Delete server"
path_params: [
{ name: "id", type: "string", required: true, description: "Server ID" }
]
}
{
method: "GET"
path: "/api/v1/ai/query"
handler: "ai_query"
description: "Natural language infrastructure queries"
parameters: [
{ name: "q", type: "string", required: true, description: "Natural language query" }
{ name: "context", type: "string", description: "Context for the query" }
]
}
{
method: "POST"
path: "/api/v1/ai/analyze"
handler: "ai_analyze"
description: "AI-powered infrastructure analysis"
body_schema: {
type: "object"
properties: {
analysis_type: { type: "string", enum: ["cost", "performance", "security", "optimization"] }
timerange: { type: "string", default: "24h" }
target: { type: "string" }
}
}
}
{
method: "GET"
path: "/api/v1/dataframes/query"
handler: "dataframe_query"
description: "Query infrastructure data using dataframes"
parameters: [
{ name: "source", type: "string", required: true, description: "Data source (logs, metrics, events)" }
{ name: "query", type: "string", required: true, description: "Polars/SQL-like query" }
{ name: "format", type: "string", default: "json", description: "Output format" }
]
}
{
method: "WebSocket"
path: "/ws/stream"
handler: "websocket_stream"
description: "Real-time updates via WebSocket"
parameters: [
{ name: "subscribe", type: "array", description: "Subscription topics" }
]
}
]
}
# Generate OpenAPI/Swagger specification
export def generate_api_spec []: nothing -> record {
let routes = get_route_definitions
{
openapi: "3.0.3"
info: {
title: "Provisioning System API"
description: "REST API for infrastructure provisioning and management"
version: "1.0.0"
contact: {
name: "Provisioning Team"
url: "https://github.com/provisioning-rs"
}
}
servers: [
{
url: "http://localhost:8080"
description: "Development server"
}
]
paths: ($routes | generate_paths)
components: {
schemas: (generate_schemas)
securitySchemes: {
BearerAuth: {
type: "http"
scheme: "bearer"
}
}
}
security: [
{ BearerAuth: [] }
]
}
}
def generate_paths []: list -> record {
let paths = {}
$in | each { |route|
let path_key = ($route.path | str replace -a "{id}" "{id}")
$paths | insert $path_key {
($route.method | str downcase): {
summary: $route.description
parameters: ($route.parameters? | default [] | each { |param|
{
name: $param.name
in: "query"
required: ($param.required? | default false)
schema: { type: $param.type }
description: $param.description?
}
})
responses: {
"200": {
description: "Successful response"
content: {
"application/json": {
schema: { type: "object" }
}
}
}
"400": {
description: "Bad request"
}
"500": {
description: "Internal server error"
}
}
}
}
} | last
}
def generate_schemas []: nothing -> record {
{
Error: {
type: "object"
properties: {
error: { type: "string" }
message: { type: "string" }
code: { type: "integer" }
}
}
HealthCheck: {
type: "object"
properties: {
status: { type: "string" }
service: { type: "string" }
version: { type: "string" }
timestamp: { type: "string" }
}
}
Server: {
type: "object"
properties: {
id: { type: "string" }
name: { type: "string" }
provider: { type: "string" }
status: { type: "string" }
ip_address: { type: "string" }
created_at: { type: "string" }
}
}
Metrics: {
type: "object"
properties: {
timestamp: { type: "string" }
cpu_usage: { type: "number" }
memory_usage: { type: "number" }
disk_usage: { type: "number" }
network_io: { type: "object" }
}
}
LogEntry: {
type: "object"
properties: {
timestamp: { type: "string" }
level: { type: "string" }
service: { type: "string" }
message: { type: "string" }
metadata: { type: "object" }
}
}
}
}
# Generate route documentation
export def generate_route_docs []: nothing -> str {
let routes = get_route_definitions
let header = "# Provisioning API Routes\n\nThis document describes all available API endpoints.\n\n"
let route_docs = ($routes | each { |route|
let params_doc = if ($route.parameters? | length) > 0 {
"\n**Parameters:**\n" + ($route.parameters | each { |p|
$"- `($p.name)` \\(($p.type)\\): ($p.description? | default 'No description')"
} | str join "\n")
} else { "" }
let body_doc = if ($route.body_schema? | is-not-empty) {
$"\n**Request Body:**\n```json\n($route.body_schema | to json)\n```"
} else { "" }
$"## ($route.method) ($route.path)\n\n($route.description)($params_doc)($body_doc)\n"
} | str join "\n")
$header + $route_docs
}
# Validate route configuration
export def validate_routes []: nothing -> record {
let routes = get_route_definitions
let validation_results = []
let path_conflicts = ($routes | group-by path | each { |path, group|
if ($group | length) > 1 {
let methods = ($group | get method)
let duplicate_methods = ($methods | uniq | length) != ($methods | length)
if $duplicate_methods {
{ path: $path, issue: "duplicate_methods", methods: $methods }
}
}
} | compact)
{
total_routes: ($routes | length)
unique_paths: ($routes | get path | uniq | length)
path_conflicts: $path_conflicts
validation_passed: ($path_conflicts | length) == 0
}
}