Update configuration files, templates, and internal documentation for the provisioning repository system. Configuration Updates: - KMS configuration modernization - Plugin system settings - Service port mappings - Test cluster topologies - Installation configuration examples - VM configuration defaults - Cedar authorization policies Documentation Updates: - Library module documentation - Extension API guides - AI system documentation - Service management guides - Test environment setup - Plugin usage guides - Validator configuration documentation All changes are backward compatible.
1089 lines
38 KiB
HTML
1089 lines
38 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en" class="ayu sidebar-visible" dir="ltr">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title>REST API - Provisioning Platform Documentation</title>
|
|
|
|
|
|
<!-- Custom HTML head -->
|
|
|
|
<meta name="description" content="Complete documentation for the Provisioning Platform - Infrastructure automation with Nushell, KCL, and Rust">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="theme-color" content="#ffffff">
|
|
|
|
<link rel="icon" href="../favicon.svg">
|
|
<link rel="shortcut icon" href="../favicon.png">
|
|
<link rel="stylesheet" href="../css/variables.css">
|
|
<link rel="stylesheet" href="../css/general.css">
|
|
<link rel="stylesheet" href="../css/chrome.css">
|
|
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
|
|
<!-- Fonts -->
|
|
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
|
|
<!-- Highlight.js Stylesheets -->
|
|
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
|
|
<!-- Custom theme stylesheets -->
|
|
|
|
|
|
<!-- Provide site root and default themes to javascript -->
|
|
<script>
|
|
const path_to_root = "../";
|
|
const default_light_theme = "ayu";
|
|
const default_dark_theme = "navy";
|
|
</script>
|
|
<!-- Start loading toc.js asap -->
|
|
<script src="../toc.js"></script>
|
|
</head>
|
|
<body>
|
|
<div id="mdbook-help-container">
|
|
<div id="mdbook-help-popup">
|
|
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
<div>
|
|
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
<p>Press <kbd>?</kbd> to show this help</p>
|
|
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="body-container">
|
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
<script>
|
|
try {
|
|
let theme = localStorage.getItem('mdbook-theme');
|
|
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
|
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
}
|
|
|
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
}
|
|
} catch (e) { }
|
|
</script>
|
|
|
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
<script>
|
|
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
let theme;
|
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
const html = document.documentElement;
|
|
html.classList.remove('ayu')
|
|
html.classList.add(theme);
|
|
html.classList.add("js");
|
|
</script>
|
|
|
|
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
|
|
<!-- Hide / unhide sidebar before it is displayed -->
|
|
<script>
|
|
let sidebar = null;
|
|
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
if (document.body.clientWidth >= 1080) {
|
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
sidebar = sidebar || 'visible';
|
|
} else {
|
|
sidebar = 'hidden';
|
|
}
|
|
sidebar_toggle.checked = sidebar === 'visible';
|
|
html.classList.remove('sidebar-visible');
|
|
html.classList.add("sidebar-" + sidebar);
|
|
</script>
|
|
|
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
<!-- populated by js -->
|
|
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
<noscript>
|
|
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
</noscript>
|
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
<div class="sidebar-resize-indicator"></div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div id="page-wrapper" class="page-wrapper">
|
|
|
|
<div class="page">
|
|
<div id="menu-bar-hover-placeholder"></div>
|
|
<div id="menu-bar" class="menu-bar sticky">
|
|
<div class="left-buttons">
|
|
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
<i class="fa fa-bars"></i>
|
|
</label>
|
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
<i class="fa fa-paint-brush"></i>
|
|
</button>
|
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
</ul>
|
|
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<h1 class="menu-title">Provisioning Platform Documentation</h1>
|
|
|
|
<div class="right-buttons">
|
|
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
<i id="print-button" class="fa fa-print"></i>
|
|
</a>
|
|
<a href="https://github.com/provisioning/provisioning-platform" title="Git repository" aria-label="Git repository">
|
|
<i id="git-repository-button" class="fa fa-github"></i>
|
|
</a>
|
|
<a href="https://github.com/provisioning/provisioning-platform/edit/main/provisioning/docs/src/api/rest-api.md" title="Suggest an edit" aria-label="Suggest an edit">
|
|
<i id="git-edit-button" class="fa fa-edit"></i>
|
|
</a>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div id="search-wrapper" class="hidden">
|
|
<form id="searchbar-outer" class="searchbar-outer">
|
|
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
</form>
|
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
<div id="searchresults-header" class="searchresults-header"></div>
|
|
<ul id="searchresults">
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
<script>
|
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
});
|
|
</script>
|
|
|
|
<div id="content" class="content">
|
|
<main>
|
|
<h1 id="rest-api-reference"><a class="header" href="#rest-api-reference">REST API Reference</a></h1>
|
|
<p>This document provides comprehensive documentation for all REST API endpoints in provisioning.</p>
|
|
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
|
|
<p>Provisioning exposes two main REST APIs:</p>
|
|
<ul>
|
|
<li><strong>Orchestrator API</strong> (Port 8080): Core workflow management and batch operations</li>
|
|
<li><strong>Control Center API</strong> (Port 9080): Authentication, authorization, and policy management</li>
|
|
</ul>
|
|
<h2 id="base-urls"><a class="header" href="#base-urls">Base URLs</a></h2>
|
|
<ul>
|
|
<li><strong>Orchestrator</strong>: <code>http://localhost:9090</code></li>
|
|
<li><strong>Control Center</strong>: <code>http://localhost:9080</code></li>
|
|
</ul>
|
|
<h2 id="authentication"><a class="header" href="#authentication">Authentication</a></h2>
|
|
<h3 id="jwt-authentication"><a class="header" href="#jwt-authentication">JWT Authentication</a></h3>
|
|
<p>All API endpoints (except health checks) require JWT authentication via the Authorization header:</p>
|
|
<pre><code class="language-http">Authorization: Bearer <jwt_token>
|
|
</code></pre>
|
|
<h3 id="getting-access-token"><a class="header" href="#getting-access-token">Getting Access Token</a></h3>
|
|
<pre><code class="language-http">POST /auth/login
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"username": "admin",
|
|
"password": "password",
|
|
"mfa_code": "123456"
|
|
}
|
|
</code></pre>
|
|
<h2 id="orchestrator-api-endpoints"><a class="header" href="#orchestrator-api-endpoints">Orchestrator API Endpoints</a></h2>
|
|
<h3 id="health-check"><a class="header" href="#health-check">Health Check</a></h3>
|
|
<h4 id="get-health"><a class="header" href="#get-health">GET /health</a></h4>
|
|
<p>Check orchestrator health status.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "Orchestrator is healthy"
|
|
}
|
|
</code></pre>
|
|
<h3 id="task-management"><a class="header" href="#task-management">Task Management</a></h3>
|
|
<h4 id="get-tasks"><a class="header" href="#get-tasks">GET /tasks</a></h4>
|
|
<p>List all workflow tasks.</p>
|
|
<p><strong>Query Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>status</code> (optional): Filter by task status (Pending, Running, Completed, Failed, Cancelled)</li>
|
|
<li><code>limit</code> (optional): Maximum number of results</li>
|
|
<li><code>offset</code> (optional): Pagination offset</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "uuid-string",
|
|
"name": "create_servers",
|
|
"command": "/usr/local/provisioning servers create",
|
|
"args": ["--infra", "production", "--wait"],
|
|
"dependencies": [],
|
|
"status": "Completed",
|
|
"created_at": "2025-09-26T10:00:00Z",
|
|
"started_at": "2025-09-26T10:00:05Z",
|
|
"completed_at": "2025-09-26T10:05:30Z",
|
|
"output": "Successfully created 3 servers",
|
|
"error": null
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<h4 id="">GET /tasks/</h4>
|
|
<p>Get specific task status and details.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: Task UUID</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"id": "uuid-string",
|
|
"name": "create_servers",
|
|
"command": "/usr/local/provisioning servers create",
|
|
"args": ["--infra", "production", "--wait"],
|
|
"dependencies": [],
|
|
"status": "Running",
|
|
"created_at": "2025-09-26T10:00:00Z",
|
|
"started_at": "2025-09-26T10:00:05Z",
|
|
"completed_at": null,
|
|
"output": null,
|
|
"error": null
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h3 id="workflow-submission"><a class="header" href="#workflow-submission">Workflow Submission</a></h3>
|
|
<h4 id="post-workflowsserverscreate"><a class="header" href="#post-workflowsserverscreate">POST /workflows/servers/create</a></h4>
|
|
<p>Submit server creation workflow.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"infra": "production",
|
|
"settings": "config.k",
|
|
"check_mode": false,
|
|
"wait": true
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "uuid-task-id"
|
|
}
|
|
</code></pre>
|
|
<h4 id="post-workflowstaskservcreate"><a class="header" href="#post-workflowstaskservcreate">POST /workflows/taskserv/create</a></h4>
|
|
<p>Submit task service workflow.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"operation": "create",
|
|
"taskserv": "kubernetes",
|
|
"infra": "production",
|
|
"settings": "config.k",
|
|
"check_mode": false,
|
|
"wait": true
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "uuid-task-id"
|
|
}
|
|
</code></pre>
|
|
<h4 id="post-workflowsclustercreate"><a class="header" href="#post-workflowsclustercreate">POST /workflows/cluster/create</a></h4>
|
|
<p>Submit cluster workflow.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"operation": "create",
|
|
"cluster_type": "buildkit",
|
|
"infra": "production",
|
|
"settings": "config.k",
|
|
"check_mode": false,
|
|
"wait": true
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "uuid-task-id"
|
|
}
|
|
</code></pre>
|
|
<h3 id="batch-operations"><a class="header" href="#batch-operations">Batch Operations</a></h3>
|
|
<h4 id="post-batchexecute"><a class="header" href="#post-batchexecute">POST /batch/execute</a></h4>
|
|
<p>Execute batch workflow operation.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"name": "multi_cloud_deployment",
|
|
"version": "1.0.0",
|
|
"storage_backend": "surrealdb",
|
|
"parallel_limit": 5,
|
|
"rollback_enabled": true,
|
|
"operations": [
|
|
{
|
|
"id": "upcloud_servers",
|
|
"type": "server_batch",
|
|
"provider": "upcloud",
|
|
"dependencies": [],
|
|
"server_configs": [
|
|
{"name": "web-01", "plan": "1xCPU-2GB", "zone": "de-fra1"},
|
|
{"name": "web-02", "plan": "1xCPU-2GB", "zone": "us-nyc1"}
|
|
]
|
|
},
|
|
{
|
|
"id": "aws_taskservs",
|
|
"type": "taskserv_batch",
|
|
"provider": "aws",
|
|
"dependencies": ["upcloud_servers"],
|
|
"taskservs": ["kubernetes", "cilium", "containerd"]
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"batch_id": "uuid-string",
|
|
"status": "Running",
|
|
"operations": [
|
|
{
|
|
"id": "upcloud_servers",
|
|
"status": "Pending",
|
|
"progress": 0.0
|
|
},
|
|
{
|
|
"id": "aws_taskservs",
|
|
"status": "Pending",
|
|
"progress": 0.0
|
|
}
|
|
]
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="get-batchoperations"><a class="header" href="#get-batchoperations">GET /batch/operations</a></h4>
|
|
<p>List all batch operations.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"batch_id": "uuid-string",
|
|
"name": "multi_cloud_deployment",
|
|
"status": "Running",
|
|
"created_at": "2025-09-26T10:00:00Z",
|
|
"operations": [...]
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<h4 id="">GET /batch/operations/</h4>
|
|
<p>Get batch operation status.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: Batch operation ID</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"batch_id": "uuid-string",
|
|
"name": "multi_cloud_deployment",
|
|
"status": "Running",
|
|
"operations": [
|
|
{
|
|
"id": "upcloud_servers",
|
|
"status": "Completed",
|
|
"progress": 100.0,
|
|
"results": {...}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="post-batchoperationsidcancel"><a class="header" href="#post-batchoperationsidcancel">POST /batch/operations/{id}/cancel</a></h4>
|
|
<p>Cancel running batch operation.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: Batch operation ID</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "Operation cancelled"
|
|
}
|
|
</code></pre>
|
|
<h3 id="state-management"><a class="header" href="#state-management">State Management</a></h3>
|
|
<h4 id="get-stateworkflowsidprogress"><a class="header" href="#get-stateworkflowsidprogress">GET /state/workflows/{id}/progress</a></h4>
|
|
<p>Get real-time workflow progress.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: Workflow ID</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"workflow_id": "uuid-string",
|
|
"progress": 75.5,
|
|
"current_step": "Installing Kubernetes",
|
|
"total_steps": 8,
|
|
"completed_steps": 6,
|
|
"estimated_time_remaining": 180
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="get-stateworkflowsidsnapshots"><a class="header" href="#get-stateworkflowsidsnapshots">GET /state/workflows/{id}/snapshots</a></h4>
|
|
<p>Get workflow state snapshots.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: Workflow ID</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"snapshot_id": "uuid-string",
|
|
"timestamp": "2025-09-26T10:00:00Z",
|
|
"state": "running",
|
|
"details": {...}
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<h4 id="get-statesystemmetrics"><a class="header" href="#get-statesystemmetrics">GET /state/system/metrics</a></h4>
|
|
<p>Get system-wide metrics.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"total_workflows": 150,
|
|
"active_workflows": 5,
|
|
"completed_workflows": 140,
|
|
"failed_workflows": 5,
|
|
"system_load": {
|
|
"cpu_usage": 45.2,
|
|
"memory_usage": 2048,
|
|
"disk_usage": 75.5
|
|
}
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="get-statesystemhealth"><a class="header" href="#get-statesystemhealth">GET /state/system/health</a></h4>
|
|
<p>Get system health status.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"overall_status": "Healthy",
|
|
"components": {
|
|
"storage": "Healthy",
|
|
"batch_coordinator": "Healthy",
|
|
"monitoring": "Healthy"
|
|
},
|
|
"last_check": "2025-09-26T10:00:00Z"
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="get-statestatistics"><a class="header" href="#get-statestatistics">GET /state/statistics</a></h4>
|
|
<p>Get state manager statistics.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"total_workflows": 150,
|
|
"active_snapshots": 25,
|
|
"storage_usage": "245MB",
|
|
"average_workflow_duration": 300
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h3 id="rollback-and-recovery"><a class="header" href="#rollback-and-recovery">Rollback and Recovery</a></h3>
|
|
<h4 id="post-rollbackcheckpoints"><a class="header" href="#post-rollbackcheckpoints">POST /rollback/checkpoints</a></h4>
|
|
<p>Create new checkpoint.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"name": "before_major_update",
|
|
"description": "Checkpoint before deploying v2.0.0"
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "checkpoint-uuid"
|
|
}
|
|
</code></pre>
|
|
<h4 id="get-rollbackcheckpoints"><a class="header" href="#get-rollbackcheckpoints">GET /rollback/checkpoints</a></h4>
|
|
<p>List all checkpoints.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "checkpoint-uuid",
|
|
"name": "before_major_update",
|
|
"description": "Checkpoint before deploying v2.0.0",
|
|
"created_at": "2025-09-26T10:00:00Z",
|
|
"size": "150MB"
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<h4 id="">GET /rollback/checkpoints/</h4>
|
|
<p>Get specific checkpoint details.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: Checkpoint ID</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"id": "checkpoint-uuid",
|
|
"name": "before_major_update",
|
|
"description": "Checkpoint before deploying v2.0.0",
|
|
"created_at": "2025-09-26T10:00:00Z",
|
|
"size": "150MB",
|
|
"operations_count": 25
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="post-rollbackexecute"><a class="header" href="#post-rollbackexecute">POST /rollback/execute</a></h4>
|
|
<p>Execute rollback operation.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"checkpoint_id": "checkpoint-uuid"
|
|
}
|
|
</code></pre>
|
|
<p>Or for partial rollback:</p>
|
|
<pre><code class="language-json">{
|
|
"operation_ids": ["op-1", "op-2", "op-3"]
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"rollback_id": "rollback-uuid",
|
|
"success": true,
|
|
"operations_executed": 25,
|
|
"operations_failed": 0,
|
|
"duration": 45.5
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="">POST /rollback/restore/</h4>
|
|
<p>Restore system state from checkpoint.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: Checkpoint ID</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "State restored from checkpoint checkpoint-uuid"
|
|
}
|
|
</code></pre>
|
|
<h4 id="get-rollbackstatistics"><a class="header" href="#get-rollbackstatistics">GET /rollback/statistics</a></h4>
|
|
<p>Get rollback system statistics.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"total_checkpoints": 10,
|
|
"total_rollbacks": 3,
|
|
"success_rate": 100.0,
|
|
"average_rollback_time": 30.5
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h2 id="control-center-api-endpoints"><a class="header" href="#control-center-api-endpoints">Control Center API Endpoints</a></h2>
|
|
<h3 id="authentication-1"><a class="header" href="#authentication-1">Authentication</a></h3>
|
|
<h4 id="post-authlogin"><a class="header" href="#post-authlogin">POST /auth/login</a></h4>
|
|
<p>Authenticate user and get JWT token.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"username": "admin",
|
|
"password": "secure_password",
|
|
"mfa_code": "123456"
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"token": "jwt-token-string",
|
|
"expires_at": "2025-09-26T18:00:00Z",
|
|
"user": {
|
|
"id": "user-uuid",
|
|
"username": "admin",
|
|
"email": "admin@example.com",
|
|
"roles": ["admin", "operator"]
|
|
}
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="post-authrefresh"><a class="header" href="#post-authrefresh">POST /auth/refresh</a></h4>
|
|
<p>Refresh JWT token.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"token": "current-jwt-token"
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"token": "new-jwt-token",
|
|
"expires_at": "2025-09-26T18:00:00Z"
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="post-authlogout"><a class="header" href="#post-authlogout">POST /auth/logout</a></h4>
|
|
<p>Logout and invalidate token.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "Successfully logged out"
|
|
}
|
|
</code></pre>
|
|
<h3 id="user-management"><a class="header" href="#user-management">User Management</a></h3>
|
|
<h4 id="get-users"><a class="header" href="#get-users">GET /users</a></h4>
|
|
<p>List all users.</p>
|
|
<p><strong>Query Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>role</code> (optional): Filter by role</li>
|
|
<li><code>enabled</code> (optional): Filter by enabled status</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "user-uuid",
|
|
"username": "admin",
|
|
"email": "admin@example.com",
|
|
"roles": ["admin"],
|
|
"enabled": true,
|
|
"created_at": "2025-09-26T10:00:00Z",
|
|
"last_login": "2025-09-26T12:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<h4 id="post-users"><a class="header" href="#post-users">POST /users</a></h4>
|
|
<p>Create new user.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"username": "newuser",
|
|
"email": "newuser@example.com",
|
|
"password": "secure_password",
|
|
"roles": ["operator"],
|
|
"enabled": true
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"id": "new-user-uuid",
|
|
"username": "newuser",
|
|
"email": "newuser@example.com",
|
|
"roles": ["operator"],
|
|
"enabled": true
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="">PUT /users/</h4>
|
|
<p>Update existing user.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: User ID</li>
|
|
</ul>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"email": "updated@example.com",
|
|
"roles": ["admin", "operator"],
|
|
"enabled": false
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "User updated successfully"
|
|
}
|
|
</code></pre>
|
|
<h4 id="">DELETE /users/</h4>
|
|
<p>Delete user.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: User ID</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "User deleted successfully"
|
|
}
|
|
</code></pre>
|
|
<h3 id="policy-management"><a class="header" href="#policy-management">Policy Management</a></h3>
|
|
<h4 id="get-policies"><a class="header" href="#get-policies">GET /policies</a></h4>
|
|
<p>List all policies.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "policy-uuid",
|
|
"name": "admin_access_policy",
|
|
"version": "1.0.0",
|
|
"rules": [...],
|
|
"created_at": "2025-09-26T10:00:00Z",
|
|
"enabled": true
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<h4 id="post-policies"><a class="header" href="#post-policies">POST /policies</a></h4>
|
|
<p>Create new policy.</p>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"name": "new_policy",
|
|
"version": "1.0.0",
|
|
"rules": [
|
|
{
|
|
"effect": "Allow",
|
|
"resource": "servers:*",
|
|
"action": ["create", "read"],
|
|
"condition": "user.role == 'admin'"
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": {
|
|
"id": "new-policy-uuid",
|
|
"name": "new_policy",
|
|
"version": "1.0.0"
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h4 id="">PUT /policies/</h4>
|
|
<p>Update policy.</p>
|
|
<p><strong>Path Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>id</code>: Policy ID</li>
|
|
</ul>
|
|
<p><strong>Request Body:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"name": "updated_policy",
|
|
"rules": [...]
|
|
}
|
|
</code></pre>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": "Policy updated successfully"
|
|
}
|
|
</code></pre>
|
|
<h3 id="audit-logging"><a class="header" href="#audit-logging">Audit Logging</a></h3>
|
|
<h4 id="get-auditlogs"><a class="header" href="#get-auditlogs">GET /audit/logs</a></h4>
|
|
<p>Get audit logs.</p>
|
|
<p><strong>Query Parameters:</strong></p>
|
|
<ul>
|
|
<li><code>user_id</code> (optional): Filter by user</li>
|
|
<li><code>action</code> (optional): Filter by action</li>
|
|
<li><code>resource</code> (optional): Filter by resource</li>
|
|
<li><code>from</code> (optional): Start date (ISO 8601)</li>
|
|
<li><code>to</code> (optional): End date (ISO 8601)</li>
|
|
<li><code>limit</code> (optional): Maximum results</li>
|
|
<li><code>offset</code> (optional): Pagination offset</li>
|
|
</ul>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "audit-log-uuid",
|
|
"timestamp": "2025-09-26T10:00:00Z",
|
|
"user_id": "user-uuid",
|
|
"action": "server.create",
|
|
"resource": "servers/web-01",
|
|
"result": "success",
|
|
"details": {...}
|
|
}
|
|
]
|
|
}
|
|
</code></pre>
|
|
<h2 id="error-responses"><a class="header" href="#error-responses">Error Responses</a></h2>
|
|
<p>All endpoints may return error responses in this format:</p>
|
|
<pre><code class="language-json">{
|
|
"success": false,
|
|
"error": "Detailed error message"
|
|
}
|
|
</code></pre>
|
|
<h3 id="http-status-codes"><a class="header" href="#http-status-codes">HTTP Status Codes</a></h3>
|
|
<ul>
|
|
<li><code>200 OK</code>: Successful request</li>
|
|
<li><code>201 Created</code>: Resource created successfully</li>
|
|
<li><code>400 Bad Request</code>: Invalid request parameters</li>
|
|
<li><code>401 Unauthorized</code>: Authentication required or invalid</li>
|
|
<li><code>403 Forbidden</code>: Permission denied</li>
|
|
<li><code>404 Not Found</code>: Resource not found</li>
|
|
<li><code>422 Unprocessable Entity</code>: Validation error</li>
|
|
<li><code>500 Internal Server Error</code>: Server error</li>
|
|
</ul>
|
|
<h2 id="rate-limiting"><a class="header" href="#rate-limiting">Rate Limiting</a></h2>
|
|
<p>API endpoints are rate-limited:</p>
|
|
<ul>
|
|
<li>Authentication: 5 requests per minute per IP</li>
|
|
<li>General APIs: 100 requests per minute per user</li>
|
|
<li>Batch operations: 10 requests per minute per user</li>
|
|
</ul>
|
|
<p>Rate limit headers are included in responses:</p>
|
|
<pre><code class="language-http">X-RateLimit-Limit: 100
|
|
X-RateLimit-Remaining: 95
|
|
X-RateLimit-Reset: 1632150000
|
|
</code></pre>
|
|
<h2 id="monitoring-endpoints"><a class="header" href="#monitoring-endpoints">Monitoring Endpoints</a></h2>
|
|
<h3 id="get-metrics"><a class="header" href="#get-metrics">GET /metrics</a></h3>
|
|
<p>Prometheus-compatible metrics endpoint.</p>
|
|
<p><strong>Response:</strong></p>
|
|
<pre><code># HELP orchestrator_tasks_total Total number of tasks
|
|
# TYPE orchestrator_tasks_total counter
|
|
orchestrator_tasks_total{status="completed"} 150
|
|
orchestrator_tasks_total{status="failed"} 5
|
|
|
|
# HELP orchestrator_task_duration_seconds Task execution duration
|
|
# TYPE orchestrator_task_duration_seconds histogram
|
|
orchestrator_task_duration_seconds_bucket{le="10"} 50
|
|
orchestrator_task_duration_seconds_bucket{le="30"} 120
|
|
orchestrator_task_duration_seconds_bucket{le="+Inf"} 155
|
|
</code></pre>
|
|
<h3 id="websocket-ws"><a class="header" href="#websocket-ws">WebSocket /ws</a></h3>
|
|
<p>Real-time event streaming via WebSocket connection.</p>
|
|
<p><strong>Connection:</strong></p>
|
|
<pre><code class="language-javascript">const ws = new WebSocket('ws://localhost:9090/ws?token=jwt-token');
|
|
|
|
ws.onmessage = function(event) {
|
|
const data = JSON.parse(event.data);
|
|
console.log('Event:', data);
|
|
};
|
|
</code></pre>
|
|
<p><strong>Event Format:</strong></p>
|
|
<pre><code class="language-json">{
|
|
"event_type": "TaskStatusChanged",
|
|
"timestamp": "2025-09-26T10:00:00Z",
|
|
"data": {
|
|
"task_id": "uuid-string",
|
|
"status": "completed"
|
|
},
|
|
"metadata": {
|
|
"task_id": "uuid-string",
|
|
"status": "completed"
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h2 id="sdk-examples"><a class="header" href="#sdk-examples">SDK Examples</a></h2>
|
|
<h3 id="python-sdk-example"><a class="header" href="#python-sdk-example">Python SDK Example</a></h3>
|
|
<pre><code class="language-python">import requests
|
|
|
|
class ProvisioningClient:
|
|
def __init__(self, base_url, token):
|
|
self.base_url = base_url
|
|
self.headers = {
|
|
'Authorization': f'Bearer {token}',
|
|
'Content-Type': 'application/json'
|
|
}
|
|
|
|
def create_server_workflow(self, infra, settings, check_mode=False):
|
|
payload = {
|
|
'infra': infra,
|
|
'settings': settings,
|
|
'check_mode': check_mode,
|
|
'wait': True
|
|
}
|
|
response = requests.post(
|
|
f'{self.base_url}/workflows/servers/create',
|
|
json=payload,
|
|
headers=self.headers
|
|
)
|
|
return response.json()
|
|
|
|
def get_task_status(self, task_id):
|
|
response = requests.get(
|
|
f'{self.base_url}/tasks/{task_id}',
|
|
headers=self.headers
|
|
)
|
|
return response.json()
|
|
|
|
# Usage
|
|
client = ProvisioningClient('http://localhost:9090', 'your-jwt-token')
|
|
result = client.create_server_workflow('production', 'config.k')
|
|
print(f"Task ID: {result['data']}")
|
|
</code></pre>
|
|
<h3 id="javascriptnodejs-sdk-example"><a class="header" href="#javascriptnodejs-sdk-example">JavaScript/Node.js SDK Example</a></h3>
|
|
<pre><code class="language-javascript">const axios = require('axios');
|
|
|
|
class ProvisioningClient {
|
|
constructor(baseUrl, token) {
|
|
this.client = axios.create({
|
|
baseURL: baseUrl,
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
}
|
|
|
|
async createServerWorkflow(infra, settings, checkMode = false) {
|
|
const response = await this.client.post('/workflows/servers/create', {
|
|
infra,
|
|
settings,
|
|
check_mode: checkMode,
|
|
wait: true
|
|
});
|
|
return response.data;
|
|
}
|
|
|
|
async getTaskStatus(taskId) {
|
|
const response = await this.client.get(`/tasks/${taskId}`);
|
|
return response.data;
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
const client = new ProvisioningClient('http://localhost:9090', 'your-jwt-token');
|
|
const result = await client.createServerWorkflow('production', 'config.k');
|
|
console.log(`Task ID: ${result.data}`);
|
|
</code></pre>
|
|
<h2 id="webhook-integration"><a class="header" href="#webhook-integration">Webhook Integration</a></h2>
|
|
<p>The system supports webhooks for external integrations:</p>
|
|
<h3 id="webhook-configuration"><a class="header" href="#webhook-configuration">Webhook Configuration</a></h3>
|
|
<p>Configure webhooks in the system configuration:</p>
|
|
<pre><code class="language-toml">[webhooks]
|
|
enabled = true
|
|
endpoints = [
|
|
{
|
|
url = "https://your-system.com/webhook"
|
|
events = ["task.completed", "task.failed", "batch.completed"]
|
|
secret = "webhook-secret"
|
|
}
|
|
]
|
|
</code></pre>
|
|
<h3 id="webhook-payload"><a class="header" href="#webhook-payload">Webhook Payload</a></h3>
|
|
<pre><code class="language-json">{
|
|
"event": "task.completed",
|
|
"timestamp": "2025-09-26T10:00:00Z",
|
|
"data": {
|
|
"task_id": "uuid-string",
|
|
"status": "completed",
|
|
"output": "Task completed successfully"
|
|
},
|
|
"signature": "sha256=calculated-signature"
|
|
}
|
|
</code></pre>
|
|
<h2 id="pagination"><a class="header" href="#pagination">Pagination</a></h2>
|
|
<p>For endpoints that return lists, use pagination parameters:</p>
|
|
<ul>
|
|
<li><code>limit</code>: Maximum number of items per page (default: 50, max: 1000)</li>
|
|
<li><code>offset</code>: Number of items to skip</li>
|
|
</ul>
|
|
<p>Pagination metadata is included in response headers:</p>
|
|
<pre><code class="language-http">X-Total-Count: 1500
|
|
X-Limit: 50
|
|
X-Offset: 100
|
|
Link: </api/endpoint?offset=150&limit=50>; rel="next"
|
|
</code></pre>
|
|
<h2 id="api-versioning"><a class="header" href="#api-versioning">API Versioning</a></h2>
|
|
<p>The API uses header-based versioning:</p>
|
|
<pre><code class="language-http">Accept: application/vnd.provisioning.v1+json
|
|
</code></pre>
|
|
<p>Current version: v1</p>
|
|
<h2 id="testing"><a class="header" href="#testing">Testing</a></h2>
|
|
<p>Use the included test suite to validate API functionality:</p>
|
|
<pre><code class="language-bash"># Run API integration tests
|
|
cd src/orchestrator
|
|
cargo test --test api_tests
|
|
|
|
# Run load tests
|
|
cargo test --test load_tests --release
|
|
</code></pre>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
<a rel="prev" href="../api/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
<a rel="next prefetch" href="../api/websocket.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
<div style="clear: both"></div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
<a rel="prev" href="../api/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
<a rel="next prefetch" href="../api/websocket.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
</nav>
|
|
|
|
</div>
|
|
|
|
<!-- Livereload script (if served using the cli tool) -->
|
|
<script>
|
|
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
|
|
const socket = new WebSocket(wsAddress);
|
|
socket.onmessage = function (event) {
|
|
if (event.data === "reload") {
|
|
socket.close();
|
|
location.reload();
|
|
}
|
|
};
|
|
|
|
window.onbeforeunload = function() {
|
|
socket.close();
|
|
}
|
|
</script>
|
|
|
|
|
|
|
|
<script>
|
|
window.playground_copyable = true;
|
|
</script>
|
|
|
|
|
|
<script src="../elasticlunr.min.js"></script>
|
|
<script src="../mark.min.js"></script>
|
|
<script src="../searcher.js"></script>
|
|
|
|
<script src="../clipboard.min.js"></script>
|
|
<script src="../highlight.js"></script>
|
|
<script src="../book.js"></script>
|
|
|
|
<!-- Custom JS scripts -->
|
|
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|