mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
feat(container): add explicit data workflows and snapshot rollback (#193)
* feat(container): add explicit data workflows and snapshot rollback Make container upgrades and recreation data-safe by adding explicit preserve, export, import, restore, and rollback flows across the backend, SDK, and web UI. * fix(container): resolve go lint issues Fix formatting and lint violations introduced by the container data workflow changes so the Go CI lint job passes cleanly.
This commit is contained in:
+259
-66
@@ -15,45 +15,6 @@ const docTemplate = `{
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/api/oauth/mcp/callback": {
|
||||
"get": {
|
||||
"description": "Handles the OAuth authorization callback, exchanges code for tokens",
|
||||
"tags": [
|
||||
"mcp"
|
||||
],
|
||||
"summary": "OAuth callback handler",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Authorization code",
|
||||
"name": "code",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "State parameter",
|
||||
"name": "state",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "HTML page that closes the popup",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/login": {
|
||||
"post": {
|
||||
"description": "Validate user credentials and issue a JWT",
|
||||
@@ -422,6 +383,12 @@ const docTemplate = `{
|
||||
"name": "bot_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "Export /data before deletion",
|
||||
"name": "preserve_data",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -443,6 +410,124 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bots/{bot_id}/container/data/export": {
|
||||
"post": {
|
||||
"produces": [
|
||||
"application/gzip"
|
||||
],
|
||||
"tags": [
|
||||
"containerd"
|
||||
],
|
||||
"summary": "Export container /data as a tar.gz archive",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Bot ID",
|
||||
"name": "bot_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "file"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bots/{bot_id}/container/data/import": {
|
||||
"post": {
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"tags": [
|
||||
"containerd"
|
||||
],
|
||||
"summary": "Import a tar.gz archive into container /data",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Bot ID",
|
||||
"name": "bot_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"description": "tar.gz archive",
|
||||
"name": "file",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bots/{bot_id}/container/data/restore": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"containerd"
|
||||
],
|
||||
"summary": "Restore previously preserved data into container",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Bot ID",
|
||||
"name": "bot_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bots/{bot_id}/container/fs": {
|
||||
"get": {
|
||||
"description": "Returns metadata about a file or directory at the given container path",
|
||||
@@ -1171,6 +1256,52 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bots/{bot_id}/container/snapshots/rollback": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"containerd"
|
||||
],
|
||||
"summary": "Rollback container to a previous snapshot version",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Bot ID",
|
||||
"name": "bot_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Rollback payload",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.RollbackRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bots/{bot_id}/container/start": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@@ -2455,6 +2586,43 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bots/{bot_id}/mcp/{id}/oauth/exchange": {
|
||||
"post": {
|
||||
"description": "Frontend callback page calls this to exchange the authorization code for access/refresh tokens",
|
||||
"tags": [
|
||||
"mcp"
|
||||
],
|
||||
"summary": "Exchange OAuth authorization code for tokens",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Authorization code and state",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.oauthExchangeRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bots/{bot_id}/mcp/{id}/oauth/status": {
|
||||
"get": {
|
||||
"description": "Returns the current OAuth status including whether tokens are available",
|
||||
@@ -8150,29 +8318,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"github_com_memohai_memoh_internal_fs.FileInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"isDir": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"modTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"github_com_memohai_memoh_internal_mcp.Connection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -8261,6 +8406,9 @@ const docTemplate = `{
|
||||
"handlers.CreateContainerRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"restore_data": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"snapshotter": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -8272,6 +8420,12 @@ const docTemplate = `{
|
||||
"container_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"data_restored": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"has_preserved_data": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"image": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -8297,6 +8451,12 @@ const docTemplate = `{
|
||||
"container_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtime_snapshot_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"snapshot_name": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -8382,7 +8542,7 @@ const docTemplate = `{
|
||||
"entries": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/github_com_memohai_memoh_internal_fs.FileInfo"
|
||||
"$ref": "#/definitions/handlers.FSFileInfo"
|
||||
}
|
||||
},
|
||||
"path": {
|
||||
@@ -8457,8 +8617,8 @@ const docTemplate = `{
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"host_path": {
|
||||
"type": "string"
|
||||
"has_preserved_data": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"image": {
|
||||
"type": "string"
|
||||
@@ -8650,6 +8810,14 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.RollbackRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.SkillItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -8710,6 +8878,9 @@ const docTemplate = `{
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -8728,6 +8899,9 @@ const docTemplate = `{
|
||||
"parent": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtime_snapshot_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"snapshotter": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -8887,8 +9061,14 @@ const docTemplate = `{
|
||||
"handlers.oauthAuthorizeRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"callback_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_secret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8900,6 +9080,17 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.oauthExchangeRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string"
|
||||
},
|
||||
"state": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.skillsOpResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -9155,6 +9346,9 @@ const docTemplate = `{
|
||||
"auth_server": {
|
||||
"type": "string"
|
||||
},
|
||||
"callback_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"configured": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -9793,7 +9987,6 @@ const docTemplate = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"api_key": {
|
||||
"description": "masked in response",
|
||||
"type": "string"
|
||||
},
|
||||
"base_url": {
|
||||
|
||||
Reference in New Issue
Block a user