This commit is contained in:
2025-05-31 11:17:56 +03:00
parent ac4db0f789
commit a96ae1252c
3 changed files with 895 additions and 25 deletions

View File

@@ -16,7 +16,7 @@
],
"methods": [
{
"name": "rpc_discover",
"name": "rpc.discover",
"description": "Returns the OpenRPC specification for the API",
"params": [],
"result": {

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.schemas.jsonrpc
import json
// Define the service status response structure based on the OpenRPC schema
struct ServiceStatus {
@@ -14,19 +15,34 @@ struct ServiceStatus {
// Create a client using the Unix socket transport
mut cl := jsonrpc.new_unix_socket_client("/tmp/zinit.sock")
// Example 1: List all services
// Example 1: Discover the API using rpc_discover
// Create a request for rpc_discover method with empty parameters
discover_request := jsonrpc.new_request_generic('rpc.discover', []string{})
// Send the request and receive the OpenRPC specification as a JSON string
println('Sending rpc_discover request...')
println('This will return the OpenRPC specification for the API')
// Use map[string]string for the result to avoid json2.Any issues
api_spec_raw := cl.send[[]string, string](discover_request)!
// Parse the JSON string manually
println('API Specification (raw):')
println(api_spec_raw)
// Example 2: List all services
// Create a request for service_list method with empty parameters
list_request := jsonrpc.new_request_generic('service_list', []string{})
// Send the request and receive a map of service names to states
println('Sending service_list request...')
println('\nSending service_list request...')
service_list := cl.send[[]string, map[string]string](list_request)!
// Display the service list
println('Service List:')
println(service_list)
// Example 2: Get status of a specific service
// Example 3: Get status of a specific service
// First, check if we have any services to query
if service_list.len > 0 {
// Get the first service name from the list
@@ -34,11 +50,11 @@ if service_list.len > 0 {
// Create a request for service_status method with the service name as parameter
// The parameter for service_status is a single string (service name)
status_request := jsonrpc.new_request_generic('service_status', {"name": service_name})
status_request := jsonrpc.new_request_generic('service_status', service_name)
// Send the request and receive a ServiceStatus object
println('\nSending service_status request for service: $service_name')
service_status := cl.send[ map[string]string, ServiceStatus](status_request)!
service_status := cl.send[string, ServiceStatus](status_request)!
// Display the service status details
println('Service Status:')
@@ -53,22 +69,3 @@ if service_list.len > 0 {
} else {
println('\nNo services found to query status')
}
// // Example 3: Alternative approach using a string array for the parameter
// // Some JSON-RPC servers expect parameters as an array, even for a single parameter
// println('\nAlternative approach using array parameter:')
// if service_list.len > 0 {
// service_name := service_list.keys()[0]
// // Create a request with the service name in an array
// status_request_alt := jsonrpc.new_request_generic('service_status', service_name)
// // Send the request and receive a ServiceStatus object
// println('Sending service_status request for service: $service_name (array parameter)')
// service_status_alt := cl.send[[]string, ServiceStatus](status_request_alt)!
// // Display the service status details
// println('Service Status (alternative):')
// println('- Name: ${service_status_alt.name}')
// println('- State: ${service_status_alt.state}')
// }

873
lib/osal/zinit/openrpc.json Normal file
View File

@@ -0,0 +1,873 @@
{
"openrpc": "1.2.6",
"info": {
"version": "1.0.0",
"title": "Zinit JSON-RPC API",
"description": "JSON-RPC 2.0 API for controlling and querying Zinit services",
"license": {
"name": "MIT"
}
},
"servers": [
{
"name": "Unix Socket",
"url": "unix:///tmp/zinit.sock"
}
],
"methods": [
{
"name": "rpc.discover",
"description": "Returns the OpenRPC specification for the API",
"params": [],
"result": {
"name": "OpenRPCSpec",
"description": "The OpenRPC specification",
"schema": {
"type": "object"
}
},
"examples": [
{
"name": "Get API specification",
"params": [],
"result": {
"name": "OpenRPCSpecResult",
"value": {
"openrpc": "1.2.6",
"info": {
"version": "1.0.0",
"title": "Zinit JSON-RPC API"
}
}
}
}
]
},
{
"name": "service_list",
"description": "Lists all services managed by Zinit",
"params": [],
"result": {
"name": "ServiceList",
"description": "A map of service names to their current states",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string",
"description": "Service state (Running, Success, Error, etc.)"
}
}
},
"examples": [
{
"name": "List all services",
"params": [],
"result": {
"name": "ServiceListResult",
"value": {
"service1": "Running",
"service2": "Success",
"service3": "Error"
}
}
}
]
},
{
"name": "service_status",
"description": "Shows detailed status information for a specific service",
"params": [
{
"name": "name",
"description": "The name of the service",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "ServiceStatus",
"description": "Detailed status information for the service",
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Service name"
},
"pid": {
"type": "integer",
"description": "Process ID of the running service (if running)"
},
"state": {
"type": "string",
"description": "Current state of the service (Running, Success, Error, etc.)"
},
"target": {
"type": "string",
"description": "Target state of the service (Up, Down)"
},
"after": {
"type": "object",
"description": "Dependencies of the service and their states",
"additionalProperties": {
"type": "string",
"description": "State of the dependency"
}
}
}
}
},
"examples": [
{
"name": "Get status of redis service",
"params": [
{
"name": "name",
"value": "redis"
}
],
"result": {
"name": "ServiceStatusResult",
"value": {
"name": "redis",
"pid": 1234,
"state": "Running",
"target": "Up",
"after": {
"dependency1": "Success",
"dependency2": "Running"
}
}
}
}
],
"errors": [
{
"code": -32000,
"message": "Service not found",
"data": "service name \"unknown\" unknown"
}
]
},
{
"name": "service_start",
"description": "Starts a service",
"params": [
{
"name": "name",
"description": "The name of the service to start",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "StartResult",
"description": "Result of the start operation",
"schema": {
"type": "null"
}
},
"examples": [
{
"name": "Start redis service",
"params": [
{
"name": "name",
"value": "redis"
}
],
"result": {
"name": "StartResult",
"value": null
}
}
],
"errors": [
{
"code": -32000,
"message": "Service not found",
"data": "service name \"unknown\" unknown"
}
]
},
{
"name": "service_stop",
"description": "Stops a service",
"params": [
{
"name": "name",
"description": "The name of the service to stop",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "StopResult",
"description": "Result of the stop operation",
"schema": {
"type": "null"
}
},
"examples": [
{
"name": "Stop redis service",
"params": [
{
"name": "name",
"value": "redis"
}
],
"result": {
"name": "StopResult",
"value": null
}
}
],
"errors": [
{
"code": -32000,
"message": "Service not found",
"data": "service name \"unknown\" unknown"
},
{
"code": -32003,
"message": "Service is down",
"data": "service \"redis\" is down"
}
]
},
{
"name": "service_monitor",
"description": "Starts monitoring a service. The service configuration is loaded from the config directory.",
"params": [
{
"name": "name",
"description": "The name of the service to monitor",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "MonitorResult",
"description": "Result of the monitor operation",
"schema": {
"type": "null"
}
},
"examples": [
{
"name": "Monitor redis service",
"params": [
{
"name": "name",
"value": "redis"
}
],
"result": {
"name": "MonitorResult",
"value": null
}
}
],
"errors": [
{
"code": -32001,
"message": "Service already monitored",
"data": "service \"redis\" already monitored"
},
{
"code": -32005,
"message": "Config error",
"data": "failed to load service configuration"
}
]
},
{
"name": "service_forget",
"description": "Stops monitoring a service. You can only forget a stopped service.",
"params": [
{
"name": "name",
"description": "The name of the service to forget",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "ForgetResult",
"description": "Result of the forget operation",
"schema": {
"type": "null"
}
},
"examples": [
{
"name": "Forget redis service",
"params": [
{
"name": "name",
"value": "redis"
}
],
"result": {
"name": "ForgetResult",
"value": null
}
}
],
"errors": [
{
"code": -32000,
"message": "Service not found",
"data": "service name \"unknown\" unknown"
},
{
"code": -32002,
"message": "Service is up",
"data": "service \"redis\" is up"
}
]
},
{
"name": "service_kill",
"description": "Sends a signal to a running service",
"params": [
{
"name": "name",
"description": "The name of the service to send the signal to",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "signal",
"description": "The signal to send (e.g., SIGTERM, SIGKILL)",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "KillResult",
"description": "Result of the kill operation",
"schema": {
"type": "null"
}
},
"examples": [
{
"name": "Send SIGTERM to redis service",
"params": [
{
"name": "name",
"value": "redis"
},
{
"name": "signal",
"value": "SIGTERM"
}
],
"result": {
"name": "KillResult",
"value": null
}
}
],
"errors": [
{
"code": -32000,
"message": "Service not found",
"data": "service name \"unknown\" unknown"
},
{
"code": -32003,
"message": "Service is down",
"data": "service \"redis\" is down"
},
{
"code": -32004,
"message": "Invalid signal",
"data": "invalid signal: INVALID"
}
]
},
{
"name": "system_shutdown",
"description": "Stops all services and powers off the system",
"params": [],
"result": {
"name": "ShutdownResult",
"description": "Result of the shutdown operation",
"schema": {
"type": "null"
}
},
"examples": [
{
"name": "Shutdown the system",
"params": [],
"result": {
"name": "ShutdownResult",
"value": null
}
}
],
"errors": [
{
"code": -32006,
"message": "Shutting down",
"data": "system is already shutting down"
}
]
},
{
"name": "system_reboot",
"description": "Stops all services and reboots the system",
"params": [],
"result": {
"name": "RebootResult",
"description": "Result of the reboot operation",
"schema": {
"type": "null"
}
},
"examples": [
{
"name": "Reboot the system",
"params": [],
"result": {
"name": "RebootResult",
"value": null
}
}
],
"errors": [
{
"code": -32006,
"message": "Shutting down",
"data": "system is already shutting down"
}
]
},
{
"name": "service_create",
"description": "Creates a new service configuration file",
"params": [
{
"name": "name",
"description": "The name of the service to create",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "content",
"description": "The service configuration content",
"required": true,
"schema": {
"type": "object",
"properties": {
"exec": {
"type": "string",
"description": "Command to run"
},
"oneshot": {
"type": "boolean",
"description": "Whether the service should be restarted"
},
"after": {
"type": "array",
"items": {
"type": "string"
},
"description": "Services that must be running before this one starts"
},
"log": {
"type": "string",
"enum": ["null", "ring", "stdout"],
"description": "How to handle service output"
},
"env": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Environment variables for the service"
},
"shutdown_timeout": {
"type": "integer",
"description": "Maximum time to wait for service to stop during shutdown"
}
}
}
}
],
"result": {
"name": "CreateServiceResult",
"description": "Result of the create operation",
"schema": {
"type": "string"
}
},
"errors": [
{
"code": -32007,
"message": "Service already exists",
"data": "Service 'name' already exists"
},
{
"code": -32008,
"message": "Service file error",
"data": "Failed to create service file"
}
]
},
{
"name": "service_delete",
"description": "Deletes a service configuration file",
"params": [
{
"name": "name",
"description": "The name of the service to delete",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "DeleteServiceResult",
"description": "Result of the delete operation",
"schema": {
"type": "string"
}
},
"errors": [
{
"code": -32000,
"message": "Service not found",
"data": "Service 'name' not found"
},
{
"code": -32008,
"message": "Service file error",
"data": "Failed to delete service file"
}
]
},
{
"name": "service_get",
"description": "Gets a service configuration file",
"params": [
{
"name": "name",
"description": "The name of the service to get",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "GetServiceResult",
"description": "The service configuration",
"schema": {
"type": "object"
}
},
"errors": [
{
"code": -32000,
"message": "Service not found",
"data": "Service 'name' not found"
},
{
"code": -32008,
"message": "Service file error",
"data": "Failed to read service file"
}
]
},
{
"name": "service_stats",
"description": "Get memory and CPU usage statistics for a service",
"params": [
{
"name": "name",
"description": "The name of the service to get stats for",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "ServiceStats",
"description": "Memory and CPU usage statistics for the service",
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Service name"
},
"pid": {
"type": "integer",
"description": "Process ID of the service"
},
"memory_usage": {
"type": "integer",
"description": "Memory usage in bytes"
},
"cpu_usage": {
"type": "number",
"description": "CPU usage as a percentage (0-100)"
},
"children": {
"type": "array",
"description": "Stats for child processes",
"items": {
"type": "object",
"properties": {
"pid": {
"type": "integer",
"description": "Process ID of the child process"
},
"memory_usage": {
"type": "integer",
"description": "Memory usage in bytes"
},
"cpu_usage": {
"type": "number",
"description": "CPU usage as a percentage (0-100)"
}
}
}
}
}
}
},
"examples": [
{
"name": "Get stats for redis service",
"params": [
{
"name": "name",
"value": "redis"
}
],
"result": {
"name": "ServiceStatsResult",
"value": {
"name": "redis",
"pid": 1234,
"memory_usage": 10485760,
"cpu_usage": 2.5,
"children": [
{
"pid": 1235,
"memory_usage": 5242880,
"cpu_usage": 1.2
}
]
}
}
}
],
"errors": [
{
"code": -32000,
"message": "Service not found",
"data": "service name \"unknown\" unknown"
},
{
"code": -32003,
"message": "Service is down",
"data": "service \"redis\" is down"
}
]
},
{
"name": "system_start_http_server",
"description": "Start an HTTP/RPC server at the specified address",
"params": [
{
"name": "address",
"description": "The network address to bind the server to (e.g., '127.0.0.1:8080')",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "StartHttpServerResult",
"description": "Result of the start HTTP server operation",
"schema": {
"type": "string"
}
},
"examples": [
{
"name": "Start HTTP server on localhost:8080",
"params": [
{
"name": "address",
"value": "127.0.0.1:8080"
}
],
"result": {
"name": "StartHttpServerResult",
"value": "HTTP server started at 127.0.0.1:8080"
}
}
],
"errors": [
{
"code": -32602,
"message": "Invalid address",
"data": "Invalid network address format"
}
]
},
{
"name": "system_stop_http_server",
"description": "Stop the HTTP/RPC server if running",
"params": [],
"result": {
"name": "StopHttpServerResult",
"description": "Result of the stop HTTP server operation",
"schema": {
"type": "null"
}
},
"examples": [
{
"name": "Stop the HTTP server",
"params": [],
"result": {
"name": "StopHttpServerResult",
"value": null
}
}
],
"errors": [
{
"code": -32602,
"message": "Server not running",
"data": "No HTTP server is currently running"
}
]
},
{
"name": "stream_currentLogs",
"description": "Get current logs from zinit and monitored services",
"params": [
{
"name": "name",
"description": "Optional service name filter. If provided, only logs from this service will be returned",
"required": false,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "LogsResult",
"description": "Array of log strings",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
"examples": [
{
"name": "Get all logs",
"params": [],
"result": {
"name": "LogsResult",
"value": [
"2023-01-01T12:00:00 redis: Starting service",
"2023-01-01T12:00:01 nginx: Starting service"
]
}
},
{
"name": "Get logs for a specific service",
"params": [
{
"name": "name",
"value": "redis"
}
],
"result": {
"name": "LogsResult",
"value": [
"2023-01-01T12:00:00 redis: Starting service",
"2023-01-01T12:00:02 redis: Service started"
]
}
}
]
},
{
"name": "stream_subscribeLogs",
"description": "Subscribe to log messages generated by zinit and monitored services",
"params": [
{
"name": "name",
"description": "Optional service name filter. If provided, only logs from this service will be returned",
"required": false,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "LogSubscription",
"description": "A subscription to log messages",
"schema": {
"type": "string"
}
},
"examples": [
{
"name": "Subscribe to all logs",
"params": [],
"result": {
"name": "LogSubscription",
"value": "2023-01-01T12:00:00 redis: Service started"
}
},
{
"name": "Subscribe to filtered logs",
"params": [
{
"name": "name",
"value": "redis"
}
],
"result": {
"name": "LogSubscription",
"value": "2023-01-01T12:00:00 redis: Service started"
}
}
]
}
]
}