diff --git a/cmd/serve.go b/cmd/serve.go index 9aefd1a..bf924a1 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -89,7 +89,7 @@ var serveCmd = &cobra.Command{ bg.BastionBootstrapArgs{}, archer.WithMaxRetries(3), // while debugging, avoid extra schedule delay: - archer.WithScheduleTime(time.Now().Add(10*time.Second)), + archer.WithScheduleTime(time.Now().Add(60*time.Second)), ) if err != nil { log.Printf("failed to enqueue bootstrap_bastion: %v", err) @@ -119,7 +119,7 @@ var serveCmd = &cobra.Command{ } }() - r := api.NewRouter(rt.DB) + r := api.NewRouter(rt.DB, jobs) addr := fmt.Sprintf("%s:%s", cfg.Host, cfg.Port) diff --git a/docs/docs.go b/docs/docs.go index 2989d53..61941da 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -5,7 +5,7 @@ package docs import "github.com/swaggo/swag/v2" const docTemplate = `{ - "schemes": {{ marshal .Schemes }},"swagger":"2.0","info":{"description":"{{escape .Description}}","title":"{{.Title}}","contact":{"name":"GlueOps"},"version":"{{.Version}}"},"host":"{{.Host}}","basePath":"{{.BasePath}}","paths":{"/.well-known/jwks.json":{"get":{"description":"Returns the JSON Web Key Set for token verification","produces":["application/json"],"tags":["Auth"],"summary":"Get JWKS","operationId":"getJWKS","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.JWKS"}}}}},"/annotations":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns annotations for the organization in X-Org-ID. Filters: ` + "`" + `name` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (name contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"List annotations (org scoped)","operationId":"ListAnnotations","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact name","name":"name","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"name contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.AnnotationResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list annotations","schema":{"type":"string"}}}}},"/annotations/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one annotation. Add ` + "`" + `include=node_pools` + "`" + ` to include node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Get annotation by ID (org scoped)","operationId":"GetAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Annotation ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"Optional: node_pools","name":"include","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AnnotationResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}}},"/auth/logout":{"post":{"consumes":["application/json"],"produces":["application/json"],"tags":["Auth"],"summary":"Revoke refresh token family (logout everywhere)","operationId":"Logout","parameters":[{"description":"Refresh token","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.LogoutRequest"}}],"responses":{"204":{"description":"No Content"}}}},"/auth/refresh":{"post":{"consumes":["application/json"],"produces":["application/json"],"tags":["Auth"],"summary":"Rotate refresh token","operationId":"Refresh","parameters":[{"description":"Refresh token","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.RefreshRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TokenPair"}}}}},"/auth/{provider}/callback":{"get":{"produces":["application/json"],"tags":["Auth"],"summary":"Handle social login callback","operationId":"AuthCallback","parameters":[{"type":"string","description":"google|github","name":"provider","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TokenPair"}}}}},"/auth/{provider}/start":{"post":{"description":"Returns provider authorization URL for the frontend to redirect","produces":["application/json"],"tags":["Auth"],"summary":"Begin social login","operationId":"AuthStart","parameters":[{"type":"string","description":"google|github","name":"provider","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AuthStartResponse"}}}}},"/healthz":{"get":{"description":"Returns 200 OK when the service is up","consumes":["application/json"],"produces":["application/json"],"tags":["Health"],"summary":"Basic health check","operationId":"HealthCheck // operationId","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.HealthStatus"}}}}},"/labels":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns node labels for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node groups.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"List node labels (org scoped)","operationId":"ListLabels","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact key","name":"key","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"Key contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.LabelResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list node taints","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Create label (org scoped)","operationId":"CreateLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Label payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateLabelRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid json / missing fields / invalid node_pool_ids","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/labels/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Get label by ID (org scoped)","operationId":"GetLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Delete label (org scoped)","operationId":"DeleteLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update label fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Update label (org scoped)","operationId":"UpdateLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateLabelRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/me":{"get":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"produces":["application/json"],"tags":["Me"],"summary":"Get current user profile","operationId":"GetMe","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.meResponse"}}}},"patch":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Me"],"summary":"Update current user profile","operationId":"UpdateMe","parameters":[{"description":"Patch profile","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.updateMeRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.User"}}}}},"/me/api-keys":{"get":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"List my API keys","operationId":"ListUserAPIKeys","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/handlers.userAPIKeyOut"}}}}},"post":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"description":"Returns the plaintext key once. Store it securely on the client side.","consumes":["application/json"],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"Create a new user API key","operationId":"CreateUserAPIKey","parameters":[{"description":"Key options","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.createUserKeyRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/handlers.userAPIKeyOut"}}}}},"/me/api-keys/{id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"Delete a user API key","operationId":"DeleteUserAPIKey","parameters":[{"type":"string","description":"Key ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content"}}}},"/orgs":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List organizations I belong to","operationId":"listMyOrgs","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/models.Organization"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Create organization","operationId":"createOrg","parameters":[{"description":"Org payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgCreateReq"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/models.Organization"}},"400":{"description":"Bad Request","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"409":{"description":"Conflict","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Get organization","operationId":"getOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.Organization"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Delete organization (owner)","operationId":"deleteOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"patch":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Update organization (owner/admin)","operationId":"updateOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"Update payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgUpdateReq"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.Organization"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/api-keys":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List org-scoped API keys (no secrets)","operationId":"listOrgKeys","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/models.APIKey"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Create org key/secret pair (owner/admin)","operationId":"createOrgKey","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"Key name + optional expiry","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgKeyCreateReq"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/handlers.orgKeyCreateResp"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/api-keys/{key_id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Delete org key (owner/admin)","operationId":"deleteOrgKey","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"Key ID (UUID)","name":"key_id","in":"path","required":true}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/members":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List members in org","operationId":"listMembers","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/handlers.memberOut"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Add or update a member (owner/admin)","operationId":"addOrUpdateMember","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"User \u0026 role","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.memberUpsertReq"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.memberOut"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/members/{user_id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Remove a member (owner/admin)","operationId":"removeMember","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"User ID (UUID)","name":"user_id","in":"path","required":true}],"responses":{"204":{"description":"Removed"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/servers":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns servers for the organization in X-Org-ID. Optional filters: status, role.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"List servers (org scoped)","operationId":"ListServers","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Filter by status (pending|provisioning|ready|failed)","name":"status","in":"query"},{"type":"string","description":"Filter by role","name":"role","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.ServerResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list servers","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Create server (org scoped)","operationId":"CreateServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Server payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateServerRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid json / missing fields / invalid status / invalid ssh_key_id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/servers/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one server in the given organization.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Get server by ID (org scoped)","operationId":"GetServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the server.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Delete server (org scoped)","operationId":"DeleteServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update fields; changing ssh_key_id validates ownership.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Update server (org scoped)","operationId":"UpdateServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateServerRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid id / invalid json / invalid status / invalid ssh_key_id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/ssh":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns ssh keys for the organization in X-Org-ID.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"List ssh keys (org scoped)","operationId":"ListPublicSshKeys","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.SshResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list keys","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Create ssh keypair (org scoped)","operationId":"CreateSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Key generation options","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateSSHRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.SshResponse"}},"400":{"description":"invalid json / invalid bits","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"generation/create failed","schema":{"type":"string"}}}}},"/ssh/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns public key fields. Append ` + "`" + `?reveal=true` + "`" + ` to include the private key PEM.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Get ssh key by ID (org scoped)","operationId":"GetSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true},{"type":"boolean","description":"Reveal private key PEM","name":"reveal","in":"query"}],"responses":{"200":{"description":"When reveal=true","schema":{"$ref":"#/definitions/dto.SshRevealResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes a keypair.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Delete ssh keypair (org scoped)","operationId":"DeleteSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}}},"/ssh/{id}/download":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Download ` + "`" + `part=public|private|both` + "`" + ` of the keypair. ` + "`" + `both` + "`" + ` returns a zip file.","produces":["application/json"],"tags":["Ssh"],"summary":"Download ssh key files by ID (org scoped)","operationId":"DownloadSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header","required":true},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true},{"enum":["public","private","both"],"type":"string","description":"Which part to download","name":"part","in":"query","required":true}],"responses":{"200":{"description":"file content","schema":{"type":"string"}},"400":{"description":"invalid id / invalid part","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"download failed","schema":{"type":"string"}}}}},"/taints":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns node taints for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"List node pool taints (org scoped)","operationId":"ListTaints","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact key","name":"key","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"key contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.TaintResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list node taints","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a taint.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Create node taint (org scoped)","operationId":"CreateTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Taint payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateTaintRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid json / missing fields / invalid node_pool_ids","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/taints/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Get node taint by ID (org scoped)","operationId":"GetTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the taint.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Delete taint (org scoped)","operationId":"DeleteTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update taint fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Update node taint (org scoped)","operationId":"UpdateTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateTaintRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}}},"definitions":{"dto.AnnotationResponse":{"type":"object","properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.AuthStartResponse":{"type":"object","properties":{"auth_url":{"type":"string","example":"https://accounts.google.com/o/oauth2/v2/auth?client_id=..."}}},"dto.CreateLabelRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.CreateSSHRequest":{"type":"object","properties":{"bits":{"description":"Only for RSA","type":"integer"},"comment":{"type":"string","example":"deploy@autoglue"},"name":{"type":"string"},"type":{"description":"\"rsa\" (default) or \"ed25519\"","type":"string"}}},"dto.CreateServerRequest":{"type":"object","properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string","example":"master|worker|bastion"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string","example":"pending|provisioning|ready|failed"}}},"dto.CreateTaintRequest":{"type":"object","properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}}},"dto.JWK":{"type":"object","properties":{"alg":{"type":"string","example":"RS256"},"e":{"type":"string","example":"AQAB"},"kid":{"type":"string","example":"7c6f1d0a-7a98-4e6a-9dbf-6b1af4b9f345"},"kty":{"type":"string","example":"RSA"},"n":{"type":"string"},"use":{"type":"string","example":"sig"},"x":{"type":"string"}}},"dto.JWKS":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/definitions/dto.JWK"}}}},"dto.LabelResponse":{"type":"object","properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.LogoutRequest":{"type":"object","properties":{"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf..."}}},"dto.RefreshRequest":{"type":"object","properties":{"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf..."}}},"dto.ServerResponse":{"type":"object","properties":{"created_at":{"type":"string"},"hostname":{"type":"string"},"id":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"}}},"dto.SshResponse":{"type":"object","properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}}},"dto.SshRevealResponse":{"type":"object","properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_key":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}}},"dto.TaintResponse":{"type":"object","properties":{"created_at":{"type":"string"},"effect":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.TokenPair":{"type":"object","properties":{"access_token":{"type":"string","example":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ij..."},"expires_in":{"type":"integer","example":3600},"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf...."},"token_type":{"type":"string","example":"Bearer"}}},"dto.UpdateLabelRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.UpdateServerRequest":{"type":"object","properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string","example":"master|worker|bastion"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string","example":"pending|provisioning|ready|failed"}}},"dto.UpdateTaintRequest":{"type":"object","properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}}},"handlers.HealthStatus":{"type":"object","properties":{"status":{"type":"string","example":"ok"}}},"handlers.createUserKeyRequest":{"type":"object","properties":{"expires_in_hours":{"description":"optional TTL","type":"integer"},"name":{"type":"string"}}},"handlers.meResponse":{"type":"object","properties":{"avatar_url":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":"string"},"emails":{"type":"array","items":{"$ref":"#/definitions/models.UserEmail"}},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_disabled":{"type":"boolean"},"organizations":{"type":"array","items":{"$ref":"#/definitions/models.Organization"}},"primary_email":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"handlers.memberOut":{"type":"object","properties":{"email":{"type":"string"},"role":{"description":"owner/admin/member","type":"string"},"user_id":{"type":"string","format":"uuid"}}},"handlers.memberUpsertReq":{"type":"object","properties":{"role":{"type":"string","example":"member"},"user_id":{"type":"string","format":"uuid"}}},"handlers.orgCreateReq":{"type":"object","properties":{"domain":{"type":"string","example":"acme.com"},"name":{"type":"string","example":"Acme Corp"}}},"handlers.orgKeyCreateReq":{"type":"object","properties":{"expires_in_hours":{"type":"integer","example":720},"name":{"type":"string","example":"automation-bot"}}},"handlers.orgKeyCreateResp":{"type":"object","properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"org_key":{"description":"shown once:","type":"string"},"org_secret":{"description":"shown once:","type":"string"},"scope":{"description":"\"org\"","type":"string"}}},"handlers.orgUpdateReq":{"type":"object","properties":{"domain":{"type":"string"},"name":{"type":"string"}}},"handlers.updateMeRequest":{"type":"object","properties":{"display_name":{"type":"string"}}},"handlers.userAPIKeyOut":{"type":"object","properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string","format":"uuid"},"last_used_at":{"type":"string"},"name":{"type":"string"},"plain":{"description":"Shown only on create:","type":"string"},"scope":{"description":"\"user\"","type":"string"}}},"models.APIKey":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"last_used_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"org_id":{"type":"string","format":"uuid"},"prefix":{"type":"string"},"revoked":{"type":"boolean"},"scope":{"type":"string"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":"string","format":"uuid"}}},"models.Organization":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"domain":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"name":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"models.User":{"type":"object","properties":{"avatar_url":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_disabled":{"type":"boolean"},"primary_email":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"models.UserEmail":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"email":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_primary":{"type":"boolean"},"is_verified":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user":{"$ref":"#/definitions/models.User"},"user_id":{"type":"string","format":"uuid"}}},"utils.ErrorResponse":{"type":"object","properties":{"code":{"description":"A machine-readable error code, e.g. \"validation_error\"\nexample: validation_error","type":"string"},"message":{"description":"Human-readable message\nexample: slug is required","type":"string"}}}},"securityDefinitions":{"ApiKeyAuth":{"description":"User API key","type":"apiKey","name":"X-API-KEY","in":"header"},"BearerAuth":{"description":"Bearer token authentication","type":"apiKey","name":"Authorization","in":"header"},"OrgKeyAuth":{"description":"Org-level key/secret authentication","type":"apiKey","name":"X-ORG-KEY","in":"header"},"OrgSecretAuth":{"description":"Org-level secret","type":"apiKey","name":"X-ORG-SECRET","in":"header"}}}` + "schemes": {{ marshal .Schemes }},"swagger":"2.0","info":{"description":"{{escape .Description}}","title":"{{.Title}}","contact":{"name":"GlueOps"},"version":"{{.Version}}"},"host":"{{.Host}}","basePath":"{{.BasePath}}","paths":{"/.well-known/jwks.json":{"get":{"description":"Returns the JSON Web Key Set for token verification","produces":["application/json"],"tags":["Auth"],"summary":"Get JWKS","operationId":"getJWKS","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.JWKS"}}}}},"/admin/archer/jobs":{"get":{"security":[{"BearerAuth":[]}],"description":"Paginated background jobs with optional filters. Search ` + "`" + `q` + "`" + ` may match id, type, error, payload (implementation-dependent).","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"List Archer jobs (admin)","operationId":"AdminListArcherJobs","parameters":[{"enum":["queued","running","succeeded","failed","canceled","retrying","scheduled"],"type":"string","description":"Filter by status","name":"status","in":"query"},{"type":"string","description":"Filter by queue name / worker name","name":"queue","in":"query"},{"type":"string","description":"Free-text search","name":"q","in":"query"},{"type":"integer","default":1,"description":"Page number","name":"page","in":"query"},{"maximum":100,"minimum":1,"type":"integer","default":25,"description":"Items per page","name":"page_size","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.PageJob"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"500":{"description":"internal error","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]}],"description":"Create a job immediately or schedule it for the future via ` + "`" + `run_at` + "`" + `.","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"Enqueue a new Archer job (admin)","operationId":"AdminEnqueueArcherJob","parameters":[{"description":"Job parameters","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.EnqueueRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.Job"}},"400":{"description":"invalid json or missing fields","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"500":{"description":"internal error","schema":{"type":"string"}}}}},"/admin/archer/jobs/{id}/cancel":{"post":{"security":[{"BearerAuth":[]}],"description":"Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill.","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"Cancel an Archer job (admin)","operationId":"AdminCancelArcherJob","parameters":[{"type":"string","description":"Job ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.Job"}},"400":{"description":"invalid job or not cancellable","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}}}}},"/admin/archer/jobs/{id}/retry":{"post":{"security":[{"BearerAuth":[]}],"description":"Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one.","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"Retry a failed/canceled Archer job (admin)","operationId":"AdminRetryArcherJob","parameters":[{"type":"string","description":"Job ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.Job"}},"400":{"description":"invalid job or not eligible","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}}}}},"/admin/archer/queues":{"get":{"security":[{"BearerAuth":[]}],"description":"Summary metrics per queue (pending, running, failed, scheduled).","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"List Archer queues (admin)","operationId":"AdminListArcherQueues","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.QueueInfo"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"500":{"description":"internal error","schema":{"type":"string"}}}}},"/annotations":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns annotations for the organization in X-Org-ID. Filters: ` + "`" + `name` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (name contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"List annotations (org scoped)","operationId":"ListAnnotations","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact name","name":"name","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"name contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.AnnotationResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list annotations","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates an annotation.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Create annotation (org scoped)","operationId":"CreateAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Annotation payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateAnnotationRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.AnnotationResponse"}},"400":{"description":"invalid json / missing fields","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/annotations/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one annotation. Add ` + "`" + `include=node_pools` + "`" + ` to include node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Get annotation by ID (org scoped)","operationId":"GetAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Annotation ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AnnotationResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the annotation.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Delete annotation (org scoped)","operationId":"DeleteAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Annotation ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update annotation fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Update annotation (org scoped)","operationId":"UpdateAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Annotation ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateAnnotationRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AnnotationResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/auth/logout":{"post":{"consumes":["application/json"],"produces":["application/json"],"tags":["Auth"],"summary":"Revoke refresh token family (logout everywhere)","operationId":"Logout","parameters":[{"description":"Refresh token","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.LogoutRequest"}}],"responses":{"204":{"description":"No Content"}}}},"/auth/refresh":{"post":{"consumes":["application/json"],"produces":["application/json"],"tags":["Auth"],"summary":"Rotate refresh token","operationId":"Refresh","parameters":[{"description":"Refresh token","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.RefreshRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TokenPair"}}}}},"/auth/{provider}/callback":{"get":{"produces":["application/json"],"tags":["Auth"],"summary":"Handle social login callback","operationId":"AuthCallback","parameters":[{"type":"string","description":"google|github","name":"provider","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TokenPair"}}}}},"/auth/{provider}/start":{"post":{"description":"Returns provider authorization URL for the frontend to redirect","produces":["application/json"],"tags":["Auth"],"summary":"Begin social login","operationId":"AuthStart","parameters":[{"type":"string","description":"google|github","name":"provider","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AuthStartResponse"}}}}},"/healthz":{"get":{"description":"Returns 200 OK when the service is up","consumes":["application/json"],"produces":["application/json"],"tags":["Health"],"summary":"Basic health check","operationId":"HealthCheck // operationId","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.HealthStatus"}}}}},"/labels":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns node labels for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node groups.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"List node labels (org scoped)","operationId":"ListLabels","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact key","name":"key","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"Key contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.LabelResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list node taints","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Create label (org scoped)","operationId":"CreateLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Label payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateLabelRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid json / missing fields / invalid node_pool_ids","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/labels/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Get label by ID (org scoped)","operationId":"GetLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Delete label (org scoped)","operationId":"DeleteLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update label fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Update label (org scoped)","operationId":"UpdateLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateLabelRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/me":{"get":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"produces":["application/json"],"tags":["Me"],"summary":"Get current user profile","operationId":"GetMe","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.meResponse"}}}},"patch":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Me"],"summary":"Update current user profile","operationId":"UpdateMe","parameters":[{"description":"Patch profile","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.updateMeRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.User"}}}}},"/me/api-keys":{"get":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"List my API keys","operationId":"ListUserAPIKeys","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/handlers.userAPIKeyOut"}}}}},"post":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"description":"Returns the plaintext key once. Store it securely on the client side.","consumes":["application/json"],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"Create a new user API key","operationId":"CreateUserAPIKey","parameters":[{"description":"Key options","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.createUserKeyRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/handlers.userAPIKeyOut"}}}}},"/me/api-keys/{id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"Delete a user API key","operationId":"DeleteUserAPIKey","parameters":[{"type":"string","description":"Key ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content"}}}},"/orgs":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List organizations I belong to","operationId":"listMyOrgs","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/models.Organization"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Create organization","operationId":"createOrg","parameters":[{"description":"Org payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgCreateReq"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/models.Organization"}},"400":{"description":"Bad Request","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"409":{"description":"Conflict","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Get organization","operationId":"getOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.Organization"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Delete organization (owner)","operationId":"deleteOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"patch":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Update organization (owner/admin)","operationId":"updateOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"Update payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgUpdateReq"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.Organization"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/api-keys":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List org-scoped API keys (no secrets)","operationId":"listOrgKeys","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/models.APIKey"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Create org key/secret pair (owner/admin)","operationId":"createOrgKey","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"Key name + optional expiry","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgKeyCreateReq"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/handlers.orgKeyCreateResp"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/api-keys/{key_id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Delete org key (owner/admin)","operationId":"deleteOrgKey","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"Key ID (UUID)","name":"key_id","in":"path","required":true}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/members":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List members in org","operationId":"listMembers","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/handlers.memberOut"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Add or update a member (owner/admin)","operationId":"addOrUpdateMember","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"User \u0026 role","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.memberUpsertReq"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.memberOut"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/members/{user_id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Remove a member (owner/admin)","operationId":"removeMember","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"User ID (UUID)","name":"user_id","in":"path","required":true}],"responses":{"204":{"description":"Removed"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/servers":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns servers for the organization in X-Org-ID. Optional filters: status, role.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"List servers (org scoped)","operationId":"ListServers","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Filter by status (pending|provisioning|ready|failed)","name":"status","in":"query"},{"type":"string","description":"Filter by role","name":"role","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.ServerResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list servers","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Create server (org scoped)","operationId":"CreateServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Server payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateServerRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid json / missing fields / invalid status / invalid ssh_key_id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/servers/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one server in the given organization.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Get server by ID (org scoped)","operationId":"GetServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the server.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Delete server (org scoped)","operationId":"DeleteServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update fields; changing ssh_key_id validates ownership.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Update server (org scoped)","operationId":"UpdateServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateServerRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid id / invalid json / invalid status / invalid ssh_key_id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/ssh":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns ssh keys for the organization in X-Org-ID.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"List ssh keys (org scoped)","operationId":"ListPublicSshKeys","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.SshResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list keys","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Create ssh keypair (org scoped)","operationId":"CreateSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Key generation options","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateSSHRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.SshResponse"}},"400":{"description":"invalid json / invalid bits","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"generation/create failed","schema":{"type":"string"}}}}},"/ssh/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns public key fields. Append ` + "`" + `?reveal=true` + "`" + ` to include the private key PEM.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Get ssh key by ID (org scoped)","operationId":"GetSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true},{"type":"boolean","description":"Reveal private key PEM","name":"reveal","in":"query"}],"responses":{"200":{"description":"When reveal=true","schema":{"$ref":"#/definitions/dto.SshRevealResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes a keypair.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Delete ssh keypair (org scoped)","operationId":"DeleteSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}}},"/ssh/{id}/download":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Download ` + "`" + `part=public|private|both` + "`" + ` of the keypair. ` + "`" + `both` + "`" + ` returns a zip file.","produces":["application/json"],"tags":["Ssh"],"summary":"Download ssh key files by ID (org scoped)","operationId":"DownloadSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header","required":true},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true},{"enum":["public","private","both"],"type":"string","description":"Which part to download","name":"part","in":"query","required":true}],"responses":{"200":{"description":"file content","schema":{"type":"string"}},"400":{"description":"invalid id / invalid part","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"download failed","schema":{"type":"string"}}}}},"/taints":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns node taints for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"List node pool taints (org scoped)","operationId":"ListTaints","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact key","name":"key","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"key contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.TaintResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list node taints","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a taint.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Create node taint (org scoped)","operationId":"CreateTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Taint payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateTaintRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid json / missing fields / invalid node_pool_ids","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/taints/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Get node taint by ID (org scoped)","operationId":"GetTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the taint.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Delete taint (org scoped)","operationId":"DeleteTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update taint fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Update node taint (org scoped)","operationId":"UpdateTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateTaintRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}}},"definitions":{"dto.AnnotationResponse":{"type":"object","properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.AuthStartResponse":{"type":"object","properties":{"auth_url":{"type":"string","example":"https://accounts.google.com/o/oauth2/v2/auth?client_id=..."}}},"dto.CreateAnnotationRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.CreateLabelRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.CreateSSHRequest":{"type":"object","properties":{"bits":{"description":"Only for RSA","type":"integer"},"comment":{"type":"string","example":"deploy@autoglue"},"name":{"type":"string"},"type":{"description":"\"rsa\" (default) or \"ed25519\"","type":"string"}}},"dto.CreateServerRequest":{"type":"object","properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string","example":"master|worker|bastion"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string","example":"pending|provisioning|ready|failed"}}},"dto.CreateTaintRequest":{"type":"object","properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}}},"dto.EnqueueRequest":{"type":"object"},"dto.JWK":{"type":"object","properties":{"alg":{"type":"string","example":"RS256"},"e":{"type":"string","example":"AQAB"},"kid":{"type":"string","example":"7c6f1d0a-7a98-4e6a-9dbf-6b1af4b9f345"},"kty":{"type":"string","example":"RSA"},"n":{"type":"string"},"use":{"type":"string","example":"sig"},"x":{"type":"string"}}},"dto.JWKS":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/definitions/dto.JWK"}}}},"dto.Job":{"type":"object","properties":{"attempts":{"type":"integer","example":0},"created_at":{"type":"string","example":"2025-11-04T09:30:00Z"},"id":{"type":"string","example":"01HF7SZK8Z8WG1M3J7S2Z8M2N6"},"last_error":{"type":"string","example":"error message"},"max_attempts":{"type":"integer","example":3},"payload":{},"queue":{"type":"string","example":"default"},"run_at":{"type":"string","example":"2025-11-04T09:30:00Z"},"status":{"enum":["queued|running|succeeded|failed|canceled|retrying|scheduled"],"allOf":[{"$ref":"#/definitions/dto.JobStatus"}],"example":"queued"},"type":{"type":"string","example":"email.send"},"updated_at":{"type":"string","example":"2025-11-04T09:30:00Z"}}},"dto.JobStatus":{"type":"string","enum":["queued","running","succeeded","failed","canceled","retrying","scheduled"],"x-enum-varnames":["StatusQueued","StatusRunning","StatusSucceeded","StatusFailed","StatusCanceled","StatusRetrying","StatusScheduled"]},"dto.LabelResponse":{"type":"object","properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.LogoutRequest":{"type":"object","properties":{"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf..."}}},"dto.PageJob":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/definitions/dto.Job"}},"page":{"type":"integer","example":1},"page_size":{"type":"integer","example":25},"total":{"type":"integer","example":120}}},"dto.QueueInfo":{"type":"object","properties":{"failed":{"type":"integer","example":5},"name":{"type":"string","example":"default"},"pending":{"type":"integer","example":42},"running":{"type":"integer","example":3},"scheduled":{"type":"integer","example":7}}},"dto.RefreshRequest":{"type":"object","properties":{"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf..."}}},"dto.ServerResponse":{"type":"object","properties":{"created_at":{"type":"string"},"hostname":{"type":"string"},"id":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"}}},"dto.SshResponse":{"type":"object","properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}}},"dto.SshRevealResponse":{"type":"object","properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_key":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}}},"dto.TaintResponse":{"type":"object","properties":{"created_at":{"type":"string"},"effect":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.TokenPair":{"type":"object","properties":{"access_token":{"type":"string","example":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ij..."},"expires_in":{"type":"integer","example":3600},"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf...."},"token_type":{"type":"string","example":"Bearer"}}},"dto.UpdateAnnotationRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.UpdateLabelRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.UpdateServerRequest":{"type":"object","properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string","example":"master|worker|bastion"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string","example":"pending|provisioning|ready|failed"}}},"dto.UpdateTaintRequest":{"type":"object","properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}}},"handlers.HealthStatus":{"type":"object","properties":{"status":{"type":"string","example":"ok"}}},"handlers.createUserKeyRequest":{"type":"object","properties":{"expires_in_hours":{"description":"optional TTL","type":"integer"},"name":{"type":"string"}}},"handlers.meResponse":{"type":"object","properties":{"avatar_url":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":"string"},"emails":{"type":"array","items":{"$ref":"#/definitions/models.UserEmail"}},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"organizations":{"type":"array","items":{"$ref":"#/definitions/models.Organization"}},"primary_email":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"handlers.memberOut":{"type":"object","properties":{"email":{"type":"string"},"role":{"description":"owner/admin/member","type":"string"},"user_id":{"type":"string","format":"uuid"}}},"handlers.memberUpsertReq":{"type":"object","properties":{"role":{"type":"string","example":"member"},"user_id":{"type":"string","format":"uuid"}}},"handlers.orgCreateReq":{"type":"object","properties":{"domain":{"type":"string","example":"acme.com"},"name":{"type":"string","example":"Acme Corp"}}},"handlers.orgKeyCreateReq":{"type":"object","properties":{"expires_in_hours":{"type":"integer","example":720},"name":{"type":"string","example":"automation-bot"}}},"handlers.orgKeyCreateResp":{"type":"object","properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"org_key":{"description":"shown once:","type":"string"},"org_secret":{"description":"shown once:","type":"string"},"scope":{"description":"\"org\"","type":"string"}}},"handlers.orgUpdateReq":{"type":"object","properties":{"domain":{"type":"string"},"name":{"type":"string"}}},"handlers.updateMeRequest":{"type":"object","properties":{"display_name":{"type":"string"}}},"handlers.userAPIKeyOut":{"type":"object","properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string","format":"uuid"},"last_used_at":{"type":"string"},"name":{"type":"string"},"plain":{"description":"Shown only on create:","type":"string"},"scope":{"description":"\"user\"","type":"string"}}},"models.APIKey":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"last_used_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"org_id":{"type":"string","format":"uuid"},"prefix":{"type":"string"},"revoked":{"type":"boolean"},"scope":{"type":"string"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":"string","format":"uuid"}}},"models.Organization":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"domain":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"name":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"models.User":{"type":"object","properties":{"avatar_url":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"primary_email":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"models.UserEmail":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"email":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_primary":{"type":"boolean"},"is_verified":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user":{"$ref":"#/definitions/models.User"},"user_id":{"type":"string","format":"uuid"}}},"utils.ErrorResponse":{"type":"object","properties":{"code":{"description":"A machine-readable error code, e.g. \"validation_error\"\nexample: validation_error","type":"string"},"message":{"description":"Human-readable message\nexample: slug is required","type":"string"}}}},"securityDefinitions":{"ApiKeyAuth":{"description":"User API key","type":"apiKey","name":"X-API-KEY","in":"header"},"BearerAuth":{"description":"Bearer token authentication","type":"apiKey","name":"Authorization","in":"header"},"OrgKeyAuth":{"description":"Org-level key/secret authentication","type":"apiKey","name":"X-ORG-KEY","in":"header"},"OrgSecretAuth":{"description":"Org-level secret","type":"apiKey","name":"X-ORG-SECRET","in":"header"}}}` // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ diff --git a/docs/swagger.json b/docs/swagger.json index def77df..a38abf1 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1 +1 @@ -{"schemes":["http","https"],"swagger":"2.0","info":{"description":"API for managing K3s clusters across cloud providers","title":"AutoGlue API","contact":{"name":"GlueOps"},"version":"1.0"},"host":"localhost:8080","basePath":"/api/v1","paths":{"/.well-known/jwks.json":{"get":{"description":"Returns the JSON Web Key Set for token verification","produces":["application/json"],"tags":["Auth"],"summary":"Get JWKS","operationId":"getJWKS","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.JWKS"}}}}},"/annotations":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns annotations for the organization in X-Org-ID. Filters: `name`, `value`, and `q` (name contains). Add `include=node_pools` to include linked node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"List annotations (org scoped)","operationId":"ListAnnotations","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact name","name":"name","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"name contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.AnnotationResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list annotations","schema":{"type":"string"}}}}},"/annotations/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one annotation. Add `include=node_pools` to include node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Get annotation by ID (org scoped)","operationId":"GetAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Annotation ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"Optional: node_pools","name":"include","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AnnotationResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}}},"/auth/logout":{"post":{"consumes":["application/json"],"produces":["application/json"],"tags":["Auth"],"summary":"Revoke refresh token family (logout everywhere)","operationId":"Logout","parameters":[{"description":"Refresh token","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.LogoutRequest"}}],"responses":{"204":{"description":"No Content"}}}},"/auth/refresh":{"post":{"consumes":["application/json"],"produces":["application/json"],"tags":["Auth"],"summary":"Rotate refresh token","operationId":"Refresh","parameters":[{"description":"Refresh token","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.RefreshRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TokenPair"}}}}},"/auth/{provider}/callback":{"get":{"produces":["application/json"],"tags":["Auth"],"summary":"Handle social login callback","operationId":"AuthCallback","parameters":[{"type":"string","description":"google|github","name":"provider","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TokenPair"}}}}},"/auth/{provider}/start":{"post":{"description":"Returns provider authorization URL for the frontend to redirect","produces":["application/json"],"tags":["Auth"],"summary":"Begin social login","operationId":"AuthStart","parameters":[{"type":"string","description":"google|github","name":"provider","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AuthStartResponse"}}}}},"/healthz":{"get":{"description":"Returns 200 OK when the service is up","consumes":["application/json"],"produces":["application/json"],"tags":["Health"],"summary":"Basic health check","operationId":"HealthCheck // operationId","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.HealthStatus"}}}}},"/labels":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns node labels for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node groups.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"List node labels (org scoped)","operationId":"ListLabels","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact key","name":"key","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"Key contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.LabelResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list node taints","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Create label (org scoped)","operationId":"CreateLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Label payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateLabelRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid json / missing fields / invalid node_pool_ids","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/labels/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Get label by ID (org scoped)","operationId":"GetLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Delete label (org scoped)","operationId":"DeleteLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update label fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Update label (org scoped)","operationId":"UpdateLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateLabelRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/me":{"get":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"produces":["application/json"],"tags":["Me"],"summary":"Get current user profile","operationId":"GetMe","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.meResponse"}}}},"patch":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Me"],"summary":"Update current user profile","operationId":"UpdateMe","parameters":[{"description":"Patch profile","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.updateMeRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.User"}}}}},"/me/api-keys":{"get":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"List my API keys","operationId":"ListUserAPIKeys","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/handlers.userAPIKeyOut"}}}}},"post":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"description":"Returns the plaintext key once. Store it securely on the client side.","consumes":["application/json"],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"Create a new user API key","operationId":"CreateUserAPIKey","parameters":[{"description":"Key options","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.createUserKeyRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/handlers.userAPIKeyOut"}}}}},"/me/api-keys/{id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"Delete a user API key","operationId":"DeleteUserAPIKey","parameters":[{"type":"string","description":"Key ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content"}}}},"/orgs":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List organizations I belong to","operationId":"listMyOrgs","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/models.Organization"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Create organization","operationId":"createOrg","parameters":[{"description":"Org payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgCreateReq"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/models.Organization"}},"400":{"description":"Bad Request","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"409":{"description":"Conflict","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Get organization","operationId":"getOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.Organization"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Delete organization (owner)","operationId":"deleteOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"patch":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Update organization (owner/admin)","operationId":"updateOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"Update payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgUpdateReq"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.Organization"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/api-keys":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List org-scoped API keys (no secrets)","operationId":"listOrgKeys","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/models.APIKey"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Create org key/secret pair (owner/admin)","operationId":"createOrgKey","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"Key name + optional expiry","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgKeyCreateReq"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/handlers.orgKeyCreateResp"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/api-keys/{key_id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Delete org key (owner/admin)","operationId":"deleteOrgKey","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"Key ID (UUID)","name":"key_id","in":"path","required":true}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/members":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List members in org","operationId":"listMembers","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/handlers.memberOut"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Add or update a member (owner/admin)","operationId":"addOrUpdateMember","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"User \u0026 role","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.memberUpsertReq"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.memberOut"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/members/{user_id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Remove a member (owner/admin)","operationId":"removeMember","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"User ID (UUID)","name":"user_id","in":"path","required":true}],"responses":{"204":{"description":"Removed"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/servers":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns servers for the organization in X-Org-ID. Optional filters: status, role.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"List servers (org scoped)","operationId":"ListServers","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Filter by status (pending|provisioning|ready|failed)","name":"status","in":"query"},{"type":"string","description":"Filter by role","name":"role","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.ServerResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list servers","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Create server (org scoped)","operationId":"CreateServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Server payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateServerRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid json / missing fields / invalid status / invalid ssh_key_id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/servers/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one server in the given organization.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Get server by ID (org scoped)","operationId":"GetServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the server.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Delete server (org scoped)","operationId":"DeleteServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update fields; changing ssh_key_id validates ownership.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Update server (org scoped)","operationId":"UpdateServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateServerRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid id / invalid json / invalid status / invalid ssh_key_id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/ssh":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns ssh keys for the organization in X-Org-ID.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"List ssh keys (org scoped)","operationId":"ListPublicSshKeys","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.SshResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list keys","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Create ssh keypair (org scoped)","operationId":"CreateSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Key generation options","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateSSHRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.SshResponse"}},"400":{"description":"invalid json / invalid bits","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"generation/create failed","schema":{"type":"string"}}}}},"/ssh/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns public key fields. Append `?reveal=true` to include the private key PEM.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Get ssh key by ID (org scoped)","operationId":"GetSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true},{"type":"boolean","description":"Reveal private key PEM","name":"reveal","in":"query"}],"responses":{"200":{"description":"When reveal=true","schema":{"$ref":"#/definitions/dto.SshRevealResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes a keypair.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Delete ssh keypair (org scoped)","operationId":"DeleteSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}}},"/ssh/{id}/download":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Download `part=public|private|both` of the keypair. `both` returns a zip file.","produces":["application/json"],"tags":["Ssh"],"summary":"Download ssh key files by ID (org scoped)","operationId":"DownloadSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header","required":true},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true},{"enum":["public","private","both"],"type":"string","description":"Which part to download","name":"part","in":"query","required":true}],"responses":{"200":{"description":"file content","schema":{"type":"string"}},"400":{"description":"invalid id / invalid part","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"download failed","schema":{"type":"string"}}}}},"/taints":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns node taints for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"List node pool taints (org scoped)","operationId":"ListTaints","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact key","name":"key","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"key contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.TaintResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list node taints","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a taint.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Create node taint (org scoped)","operationId":"CreateTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Taint payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateTaintRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid json / missing fields / invalid node_pool_ids","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/taints/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Get node taint by ID (org scoped)","operationId":"GetTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the taint.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Delete taint (org scoped)","operationId":"DeleteTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update taint fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Update node taint (org scoped)","operationId":"UpdateTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateTaintRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}}},"definitions":{"dto.AnnotationResponse":{"type":"object","properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.AuthStartResponse":{"type":"object","properties":{"auth_url":{"type":"string","example":"https://accounts.google.com/o/oauth2/v2/auth?client_id=..."}}},"dto.CreateLabelRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.CreateSSHRequest":{"type":"object","properties":{"bits":{"description":"Only for RSA","type":"integer"},"comment":{"type":"string","example":"deploy@autoglue"},"name":{"type":"string"},"type":{"description":"\"rsa\" (default) or \"ed25519\"","type":"string"}}},"dto.CreateServerRequest":{"type":"object","properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string","example":"master|worker|bastion"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string","example":"pending|provisioning|ready|failed"}}},"dto.CreateTaintRequest":{"type":"object","properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}}},"dto.JWK":{"type":"object","properties":{"alg":{"type":"string","example":"RS256"},"e":{"type":"string","example":"AQAB"},"kid":{"type":"string","example":"7c6f1d0a-7a98-4e6a-9dbf-6b1af4b9f345"},"kty":{"type":"string","example":"RSA"},"n":{"type":"string"},"use":{"type":"string","example":"sig"},"x":{"type":"string"}}},"dto.JWKS":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/definitions/dto.JWK"}}}},"dto.LabelResponse":{"type":"object","properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.LogoutRequest":{"type":"object","properties":{"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf..."}}},"dto.RefreshRequest":{"type":"object","properties":{"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf..."}}},"dto.ServerResponse":{"type":"object","properties":{"created_at":{"type":"string"},"hostname":{"type":"string"},"id":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"}}},"dto.SshResponse":{"type":"object","properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}}},"dto.SshRevealResponse":{"type":"object","properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_key":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}}},"dto.TaintResponse":{"type":"object","properties":{"created_at":{"type":"string"},"effect":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.TokenPair":{"type":"object","properties":{"access_token":{"type":"string","example":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ij..."},"expires_in":{"type":"integer","example":3600},"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf...."},"token_type":{"type":"string","example":"Bearer"}}},"dto.UpdateLabelRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.UpdateServerRequest":{"type":"object","properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string","example":"master|worker|bastion"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string","example":"pending|provisioning|ready|failed"}}},"dto.UpdateTaintRequest":{"type":"object","properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}}},"handlers.HealthStatus":{"type":"object","properties":{"status":{"type":"string","example":"ok"}}},"handlers.createUserKeyRequest":{"type":"object","properties":{"expires_in_hours":{"description":"optional TTL","type":"integer"},"name":{"type":"string"}}},"handlers.meResponse":{"type":"object","properties":{"avatar_url":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":"string"},"emails":{"type":"array","items":{"$ref":"#/definitions/models.UserEmail"}},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_disabled":{"type":"boolean"},"organizations":{"type":"array","items":{"$ref":"#/definitions/models.Organization"}},"primary_email":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"handlers.memberOut":{"type":"object","properties":{"email":{"type":"string"},"role":{"description":"owner/admin/member","type":"string"},"user_id":{"type":"string","format":"uuid"}}},"handlers.memberUpsertReq":{"type":"object","properties":{"role":{"type":"string","example":"member"},"user_id":{"type":"string","format":"uuid"}}},"handlers.orgCreateReq":{"type":"object","properties":{"domain":{"type":"string","example":"acme.com"},"name":{"type":"string","example":"Acme Corp"}}},"handlers.orgKeyCreateReq":{"type":"object","properties":{"expires_in_hours":{"type":"integer","example":720},"name":{"type":"string","example":"automation-bot"}}},"handlers.orgKeyCreateResp":{"type":"object","properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"org_key":{"description":"shown once:","type":"string"},"org_secret":{"description":"shown once:","type":"string"},"scope":{"description":"\"org\"","type":"string"}}},"handlers.orgUpdateReq":{"type":"object","properties":{"domain":{"type":"string"},"name":{"type":"string"}}},"handlers.updateMeRequest":{"type":"object","properties":{"display_name":{"type":"string"}}},"handlers.userAPIKeyOut":{"type":"object","properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string","format":"uuid"},"last_used_at":{"type":"string"},"name":{"type":"string"},"plain":{"description":"Shown only on create:","type":"string"},"scope":{"description":"\"user\"","type":"string"}}},"models.APIKey":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"last_used_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"org_id":{"type":"string","format":"uuid"},"prefix":{"type":"string"},"revoked":{"type":"boolean"},"scope":{"type":"string"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":"string","format":"uuid"}}},"models.Organization":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"domain":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"name":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"models.User":{"type":"object","properties":{"avatar_url":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_disabled":{"type":"boolean"},"primary_email":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"models.UserEmail":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"email":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_primary":{"type":"boolean"},"is_verified":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user":{"$ref":"#/definitions/models.User"},"user_id":{"type":"string","format":"uuid"}}},"utils.ErrorResponse":{"type":"object","properties":{"code":{"description":"A machine-readable error code, e.g. \"validation_error\"\nexample: validation_error","type":"string"},"message":{"description":"Human-readable message\nexample: slug is required","type":"string"}}}},"securityDefinitions":{"ApiKeyAuth":{"description":"User API key","type":"apiKey","name":"X-API-KEY","in":"header"},"BearerAuth":{"description":"Bearer token authentication","type":"apiKey","name":"Authorization","in":"header"},"OrgKeyAuth":{"description":"Org-level key/secret authentication","type":"apiKey","name":"X-ORG-KEY","in":"header"},"OrgSecretAuth":{"description":"Org-level secret","type":"apiKey","name":"X-ORG-SECRET","in":"header"}}} \ No newline at end of file +{"schemes":["http","https"],"swagger":"2.0","info":{"description":"API for managing K3s clusters across cloud providers","title":"AutoGlue API","contact":{"name":"GlueOps"},"version":"1.0"},"host":"localhost:8080","basePath":"/api/v1","paths":{"/.well-known/jwks.json":{"get":{"description":"Returns the JSON Web Key Set for token verification","produces":["application/json"],"tags":["Auth"],"summary":"Get JWKS","operationId":"getJWKS","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.JWKS"}}}}},"/admin/archer/jobs":{"get":{"security":[{"BearerAuth":[]}],"description":"Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent).","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"List Archer jobs (admin)","operationId":"AdminListArcherJobs","parameters":[{"enum":["queued","running","succeeded","failed","canceled","retrying","scheduled"],"type":"string","description":"Filter by status","name":"status","in":"query"},{"type":"string","description":"Filter by queue name / worker name","name":"queue","in":"query"},{"type":"string","description":"Free-text search","name":"q","in":"query"},{"type":"integer","default":1,"description":"Page number","name":"page","in":"query"},{"maximum":100,"minimum":1,"type":"integer","default":25,"description":"Items per page","name":"page_size","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.PageJob"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"500":{"description":"internal error","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]}],"description":"Create a job immediately or schedule it for the future via `run_at`.","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"Enqueue a new Archer job (admin)","operationId":"AdminEnqueueArcherJob","parameters":[{"description":"Job parameters","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.EnqueueRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.Job"}},"400":{"description":"invalid json or missing fields","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"500":{"description":"internal error","schema":{"type":"string"}}}}},"/admin/archer/jobs/{id}/cancel":{"post":{"security":[{"BearerAuth":[]}],"description":"Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill.","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"Cancel an Archer job (admin)","operationId":"AdminCancelArcherJob","parameters":[{"type":"string","description":"Job ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.Job"}},"400":{"description":"invalid job or not cancellable","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}}}}},"/admin/archer/jobs/{id}/retry":{"post":{"security":[{"BearerAuth":[]}],"description":"Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one.","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"Retry a failed/canceled Archer job (admin)","operationId":"AdminRetryArcherJob","parameters":[{"type":"string","description":"Job ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.Job"}},"400":{"description":"invalid job or not eligible","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}}}}},"/admin/archer/queues":{"get":{"security":[{"BearerAuth":[]}],"description":"Summary metrics per queue (pending, running, failed, scheduled).","consumes":["application/json"],"produces":["application/json"],"tags":["ArcherAdmin"],"summary":"List Archer queues (admin)","operationId":"AdminListArcherQueues","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.QueueInfo"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"forbidden","schema":{"type":"string"}},"500":{"description":"internal error","schema":{"type":"string"}}}}},"/annotations":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns annotations for the organization in X-Org-ID. Filters: `name`, `value`, and `q` (name contains). Add `include=node_pools` to include linked node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"List annotations (org scoped)","operationId":"ListAnnotations","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact name","name":"name","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"name contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.AnnotationResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list annotations","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates an annotation.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Create annotation (org scoped)","operationId":"CreateAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Annotation payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateAnnotationRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.AnnotationResponse"}},"400":{"description":"invalid json / missing fields","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/annotations/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one annotation. Add `include=node_pools` to include node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Get annotation by ID (org scoped)","operationId":"GetAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Annotation ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AnnotationResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the annotation.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Delete annotation (org scoped)","operationId":"DeleteAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Annotation ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update annotation fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Annotations"],"summary":"Update annotation (org scoped)","operationId":"UpdateAnnotation","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Annotation ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateAnnotationRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AnnotationResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/auth/logout":{"post":{"consumes":["application/json"],"produces":["application/json"],"tags":["Auth"],"summary":"Revoke refresh token family (logout everywhere)","operationId":"Logout","parameters":[{"description":"Refresh token","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.LogoutRequest"}}],"responses":{"204":{"description":"No Content"}}}},"/auth/refresh":{"post":{"consumes":["application/json"],"produces":["application/json"],"tags":["Auth"],"summary":"Rotate refresh token","operationId":"Refresh","parameters":[{"description":"Refresh token","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.RefreshRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TokenPair"}}}}},"/auth/{provider}/callback":{"get":{"produces":["application/json"],"tags":["Auth"],"summary":"Handle social login callback","operationId":"AuthCallback","parameters":[{"type":"string","description":"google|github","name":"provider","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TokenPair"}}}}},"/auth/{provider}/start":{"post":{"description":"Returns provider authorization URL for the frontend to redirect","produces":["application/json"],"tags":["Auth"],"summary":"Begin social login","operationId":"AuthStart","parameters":[{"type":"string","description":"google|github","name":"provider","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.AuthStartResponse"}}}}},"/healthz":{"get":{"description":"Returns 200 OK when the service is up","consumes":["application/json"],"produces":["application/json"],"tags":["Health"],"summary":"Basic health check","operationId":"HealthCheck // operationId","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.HealthStatus"}}}}},"/labels":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns node labels for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node groups.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"List node labels (org scoped)","operationId":"ListLabels","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact key","name":"key","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"Key contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.LabelResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list node taints","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Create label (org scoped)","operationId":"CreateLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Label payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateLabelRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid json / missing fields / invalid node_pool_ids","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/labels/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Get label by ID (org scoped)","operationId":"GetLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the label.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Delete label (org scoped)","operationId":"DeleteLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update label fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Labels"],"summary":"Update label (org scoped)","operationId":"UpdateLabel","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Label ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateLabelRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.LabelResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/me":{"get":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"produces":["application/json"],"tags":["Me"],"summary":"Get current user profile","operationId":"GetMe","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.meResponse"}}}},"patch":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Me"],"summary":"Update current user profile","operationId":"UpdateMe","parameters":[{"description":"Patch profile","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.updateMeRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.User"}}}}},"/me/api-keys":{"get":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"List my API keys","operationId":"ListUserAPIKeys","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/handlers.userAPIKeyOut"}}}}},"post":{"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"description":"Returns the plaintext key once. Store it securely on the client side.","consumes":["application/json"],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"Create a new user API key","operationId":"CreateUserAPIKey","parameters":[{"description":"Key options","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.createUserKeyRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/handlers.userAPIKeyOut"}}}}},"/me/api-keys/{id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["MeAPIKeys"],"summary":"Delete a user API key","operationId":"DeleteUserAPIKey","parameters":[{"type":"string","description":"Key ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content"}}}},"/orgs":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List organizations I belong to","operationId":"listMyOrgs","responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/models.Organization"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Create organization","operationId":"createOrg","parameters":[{"description":"Org payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgCreateReq"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/models.Organization"}},"400":{"description":"Bad Request","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"409":{"description":"Conflict","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Get organization","operationId":"getOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.Organization"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Delete organization (owner)","operationId":"deleteOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"patch":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Update organization (owner/admin)","operationId":"updateOrg","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"Update payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgUpdateReq"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/models.Organization"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/api-keys":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List org-scoped API keys (no secrets)","operationId":"listOrgKeys","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/models.APIKey"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Create org key/secret pair (owner/admin)","operationId":"createOrgKey","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"Key name + optional expiry","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.orgKeyCreateReq"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/handlers.orgKeyCreateResp"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/api-keys/{key_id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Delete org key (owner/admin)","operationId":"deleteOrgKey","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"Key ID (UUID)","name":"key_id","in":"path","required":true}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/members":{"get":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"List members in org","operationId":"listMembers","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/handlers.memberOut"}}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}},"post":{"security":[{"BearerAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Orgs"],"summary":"Add or update a member (owner/admin)","operationId":"addOrUpdateMember","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"description":"User \u0026 role","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/handlers.memberUpsertReq"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/handlers.memberOut"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/orgs/{id}/members/{user_id}":{"delete":{"security":[{"BearerAuth":[]}],"produces":["application/json"],"tags":["Orgs"],"summary":"Remove a member (owner/admin)","operationId":"removeMember","parameters":[{"type":"string","description":"Org ID (UUID)","name":"id","in":"path","required":true},{"type":"string","description":"User ID (UUID)","name":"user_id","in":"path","required":true}],"responses":{"204":{"description":"Removed"},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/utils.ErrorResponse"}}}}},"/servers":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns servers for the organization in X-Org-ID. Optional filters: status, role.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"List servers (org scoped)","operationId":"ListServers","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Filter by status (pending|provisioning|ready|failed)","name":"status","in":"query"},{"type":"string","description":"Filter by role","name":"role","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.ServerResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list servers","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Create server (org scoped)","operationId":"CreateServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Server payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateServerRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid json / missing fields / invalid status / invalid ssh_key_id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/servers/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns one server in the given organization.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Get server by ID (org scoped)","operationId":"GetServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the server.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Delete server (org scoped)","operationId":"DeleteServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update fields; changing ssh_key_id validates ownership.","consumes":["application/json"],"produces":["application/json"],"tags":["Servers"],"summary":"Update server (org scoped)","operationId":"UpdateServer","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Server ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateServerRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.ServerResponse"}},"400":{"description":"invalid id / invalid json / invalid status / invalid ssh_key_id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}},"/ssh":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns ssh keys for the organization in X-Org-ID.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"List ssh keys (org scoped)","operationId":"ListPublicSshKeys","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.SshResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list keys","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Create ssh keypair (org scoped)","operationId":"CreateSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Key generation options","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateSSHRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.SshResponse"}},"400":{"description":"invalid json / invalid bits","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"generation/create failed","schema":{"type":"string"}}}}},"/ssh/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns public key fields. Append `?reveal=true` to include the private key PEM.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Get ssh key by ID (org scoped)","operationId":"GetSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true},{"type":"boolean","description":"Reveal private key PEM","name":"reveal","in":"query"}],"responses":{"200":{"description":"When reveal=true","schema":{"$ref":"#/definitions/dto.SshRevealResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes a keypair.","consumes":["application/json"],"produces":["application/json"],"tags":["Ssh"],"summary":"Delete ssh keypair (org scoped)","operationId":"DeleteSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}}},"/ssh/{id}/download":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Download `part=public|private|both` of the keypair. `both` returns a zip file.","produces":["application/json"],"tags":["Ssh"],"summary":"Download ssh key files by ID (org scoped)","operationId":"DownloadSSHKey","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header","required":true},{"type":"string","description":"SSH Key ID (UUID)","name":"id","in":"path","required":true},{"enum":["public","private","both"],"type":"string","description":"Which part to download","name":"part","in":"query","required":true}],"responses":{"200":{"description":"file content","schema":{"type":"string"}},"400":{"description":"invalid id / invalid part","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"download failed","schema":{"type":"string"}}}}},"/taints":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Returns node taints for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"List node pool taints (org scoped)","operationId":"ListTaints","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Exact key","name":"key","in":"query"},{"type":"string","description":"Exact value","name":"value","in":"query"},{"type":"string","description":"key contains (case-insensitive)","name":"q","in":"query"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/dto.TaintResponse"}}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"failed to list node taints","schema":{"type":"string"}}}},"post":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Creates a taint.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Create node taint (org scoped)","operationId":"CreateTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"description":"Taint payload","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.CreateTaintRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid json / missing fields / invalid node_pool_ids","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"create failed","schema":{"type":"string"}}}}},"/taints/{id}":{"get":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Get node taint by ID (org scoped)","operationId":"GetTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"fetch failed","schema":{"type":"string"}}}},"delete":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Permanently deletes the taint.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Delete taint (org scoped)","operationId":"DeleteTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"invalid id","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"500":{"description":"delete failed","schema":{"type":"string"}}}},"patch":{"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"description":"Partially update taint fields.","consumes":["application/json"],"produces":["application/json"],"tags":["Taints"],"summary":"Update node taint (org scoped)","operationId":"UpdateTaint","parameters":[{"type":"string","description":"Organization UUID","name":"X-Org-ID","in":"header"},{"type":"string","description":"Node Taint ID (UUID)","name":"id","in":"path","required":true},{"description":"Fields to update","name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/dto.UpdateTaintRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/dto.TaintResponse"}},"400":{"description":"invalid id / invalid json","schema":{"type":"string"}},"401":{"description":"Unauthorized","schema":{"type":"string"}},"403":{"description":"organization required","schema":{"type":"string"}},"404":{"description":"not found","schema":{"type":"string"}},"500":{"description":"update failed","schema":{"type":"string"}}}}}},"definitions":{"dto.AnnotationResponse":{"type":"object","properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.AuthStartResponse":{"type":"object","properties":{"auth_url":{"type":"string","example":"https://accounts.google.com/o/oauth2/v2/auth?client_id=..."}}},"dto.CreateAnnotationRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.CreateLabelRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.CreateSSHRequest":{"type":"object","properties":{"bits":{"description":"Only for RSA","type":"integer"},"comment":{"type":"string","example":"deploy@autoglue"},"name":{"type":"string"},"type":{"description":"\"rsa\" (default) or \"ed25519\"","type":"string"}}},"dto.CreateServerRequest":{"type":"object","properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string","example":"master|worker|bastion"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string","example":"pending|provisioning|ready|failed"}}},"dto.CreateTaintRequest":{"type":"object","properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}}},"dto.EnqueueRequest":{"type":"object"},"dto.JWK":{"type":"object","properties":{"alg":{"type":"string","example":"RS256"},"e":{"type":"string","example":"AQAB"},"kid":{"type":"string","example":"7c6f1d0a-7a98-4e6a-9dbf-6b1af4b9f345"},"kty":{"type":"string","example":"RSA"},"n":{"type":"string"},"use":{"type":"string","example":"sig"},"x":{"type":"string"}}},"dto.JWKS":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/definitions/dto.JWK"}}}},"dto.Job":{"type":"object","properties":{"attempts":{"type":"integer","example":0},"created_at":{"type":"string","example":"2025-11-04T09:30:00Z"},"id":{"type":"string","example":"01HF7SZK8Z8WG1M3J7S2Z8M2N6"},"last_error":{"type":"string","example":"error message"},"max_attempts":{"type":"integer","example":3},"payload":{},"queue":{"type":"string","example":"default"},"run_at":{"type":"string","example":"2025-11-04T09:30:00Z"},"status":{"enum":["queued|running|succeeded|failed|canceled|retrying|scheduled"],"allOf":[{"$ref":"#/definitions/dto.JobStatus"}],"example":"queued"},"type":{"type":"string","example":"email.send"},"updated_at":{"type":"string","example":"2025-11-04T09:30:00Z"}}},"dto.JobStatus":{"type":"string","enum":["queued","running","succeeded","failed","canceled","retrying","scheduled"],"x-enum-varnames":["StatusQueued","StatusRunning","StatusSucceeded","StatusFailed","StatusCanceled","StatusRetrying","StatusScheduled"]},"dto.LabelResponse":{"type":"object","properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.LogoutRequest":{"type":"object","properties":{"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf..."}}},"dto.PageJob":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/definitions/dto.Job"}},"page":{"type":"integer","example":1},"page_size":{"type":"integer","example":25},"total":{"type":"integer","example":120}}},"dto.QueueInfo":{"type":"object","properties":{"failed":{"type":"integer","example":5},"name":{"type":"string","example":"default"},"pending":{"type":"integer","example":42},"running":{"type":"integer","example":3},"scheduled":{"type":"integer","example":7}}},"dto.RefreshRequest":{"type":"object","properties":{"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf..."}}},"dto.ServerResponse":{"type":"object","properties":{"created_at":{"type":"string"},"hostname":{"type":"string"},"id":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"}}},"dto.SshResponse":{"type":"object","properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}}},"dto.SshRevealResponse":{"type":"object","properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_key":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}}},"dto.TaintResponse":{"type":"object","properties":{"created_at":{"type":"string"},"effect":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}}},"dto.TokenPair":{"type":"object","properties":{"access_token":{"type":"string","example":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ij..."},"expires_in":{"type":"integer","example":3600},"refresh_token":{"type":"string","example":"m0l9o8rT3t0V8d3eFf...."},"token_type":{"type":"string","example":"Bearer"}}},"dto.UpdateAnnotationRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.UpdateLabelRequest":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"dto.UpdateServerRequest":{"type":"object","properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"type":"string","example":"master|worker|bastion"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"type":"string","example":"pending|provisioning|ready|failed"}}},"dto.UpdateTaintRequest":{"type":"object","properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}}},"handlers.HealthStatus":{"type":"object","properties":{"status":{"type":"string","example":"ok"}}},"handlers.createUserKeyRequest":{"type":"object","properties":{"expires_in_hours":{"description":"optional TTL","type":"integer"},"name":{"type":"string"}}},"handlers.meResponse":{"type":"object","properties":{"avatar_url":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":"string"},"emails":{"type":"array","items":{"$ref":"#/definitions/models.UserEmail"}},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"organizations":{"type":"array","items":{"$ref":"#/definitions/models.Organization"}},"primary_email":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"handlers.memberOut":{"type":"object","properties":{"email":{"type":"string"},"role":{"description":"owner/admin/member","type":"string"},"user_id":{"type":"string","format":"uuid"}}},"handlers.memberUpsertReq":{"type":"object","properties":{"role":{"type":"string","example":"member"},"user_id":{"type":"string","format":"uuid"}}},"handlers.orgCreateReq":{"type":"object","properties":{"domain":{"type":"string","example":"acme.com"},"name":{"type":"string","example":"Acme Corp"}}},"handlers.orgKeyCreateReq":{"type":"object","properties":{"expires_in_hours":{"type":"integer","example":720},"name":{"type":"string","example":"automation-bot"}}},"handlers.orgKeyCreateResp":{"type":"object","properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"org_key":{"description":"shown once:","type":"string"},"org_secret":{"description":"shown once:","type":"string"},"scope":{"description":"\"org\"","type":"string"}}},"handlers.orgUpdateReq":{"type":"object","properties":{"domain":{"type":"string"},"name":{"type":"string"}}},"handlers.updateMeRequest":{"type":"object","properties":{"display_name":{"type":"string"}}},"handlers.userAPIKeyOut":{"type":"object","properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string","format":"uuid"},"last_used_at":{"type":"string"},"name":{"type":"string"},"plain":{"description":"Shown only on create:","type":"string"},"scope":{"description":"\"user\"","type":"string"}}},"models.APIKey":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"last_used_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"org_id":{"type":"string","format":"uuid"},"prefix":{"type":"string"},"revoked":{"type":"boolean"},"scope":{"type":"string"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":"string","format":"uuid"}}},"models.Organization":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"domain":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"name":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"models.User":{"type":"object","properties":{"avatar_url":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"primary_email":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"models.UserEmail":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"email":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","type":"string","format":"uuid"},"is_primary":{"type":"boolean"},"is_verified":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user":{"$ref":"#/definitions/models.User"},"user_id":{"type":"string","format":"uuid"}}},"utils.ErrorResponse":{"type":"object","properties":{"code":{"description":"A machine-readable error code, e.g. \"validation_error\"\nexample: validation_error","type":"string"},"message":{"description":"Human-readable message\nexample: slug is required","type":"string"}}}},"securityDefinitions":{"ApiKeyAuth":{"description":"User API key","type":"apiKey","name":"X-API-KEY","in":"header"},"BearerAuth":{"description":"Bearer token authentication","type":"apiKey","name":"Authorization","in":"header"},"OrgKeyAuth":{"description":"Org-level key/secret authentication","type":"apiKey","name":"X-ORG-KEY","in":"header"},"OrgSecretAuth":{"description":"Org-level secret","type":"apiKey","name":"X-ORG-SECRET","in":"header"}}} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 77fa08c..aab9799 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -21,6 +21,13 @@ definitions: example: https://accounts.google.com/o/oauth2/v2/auth?client_id=... type: string type: object + dto.CreateAnnotationRequest: + properties: + key: + type: string + value: + type: string + type: object dto.CreateLabelRequest: properties: key: @@ -70,6 +77,8 @@ definitions: value: type: string type: object + dto.EnqueueRequest: + type: object dto.JWK: properties: alg: @@ -99,6 +108,61 @@ definitions: $ref: '#/definitions/dto.JWK' type: array type: object + dto.Job: + properties: + attempts: + example: 0 + type: integer + created_at: + example: "2025-11-04T09:30:00Z" + type: string + id: + example: 01HF7SZK8Z8WG1M3J7S2Z8M2N6 + type: string + last_error: + example: error message + type: string + max_attempts: + example: 3 + type: integer + payload: {} + queue: + example: default + type: string + run_at: + example: "2025-11-04T09:30:00Z" + type: string + status: + allOf: + - $ref: '#/definitions/dto.JobStatus' + enum: + - queued|running|succeeded|failed|canceled|retrying|scheduled + example: queued + type: + example: email.send + type: string + updated_at: + example: "2025-11-04T09:30:00Z" + type: string + type: object + dto.JobStatus: + enum: + - queued + - running + - succeeded + - failed + - canceled + - retrying + - scheduled + type: string + x-enum-varnames: + - StatusQueued + - StatusRunning + - StatusSucceeded + - StatusFailed + - StatusCanceled + - StatusRetrying + - StatusScheduled dto.LabelResponse: properties: created_at: @@ -120,6 +184,40 @@ definitions: example: m0l9o8rT3t0V8d3eFf... type: string type: object + dto.PageJob: + properties: + items: + items: + $ref: '#/definitions/dto.Job' + type: array + page: + example: 1 + type: integer + page_size: + example: 25 + type: integer + total: + example: 120 + type: integer + type: object + dto.QueueInfo: + properties: + failed: + example: 5 + type: integer + name: + example: default + type: string + pending: + example: 42 + type: integer + running: + example: 3 + type: integer + scheduled: + example: 7 + type: integer + type: object dto.RefreshRequest: properties: refresh_token: @@ -219,6 +317,13 @@ definitions: example: Bearer type: string type: object + dto.UpdateAnnotationRequest: + properties: + key: + type: string + value: + type: string + type: object dto.UpdateLabelRequest: properties: key: @@ -285,6 +390,8 @@ definitions: description: 'example: 3fa85f64-5717-4562-b3fc-2c963f66afa6' format: uuid type: string + is_admin: + type: boolean is_disabled: type: boolean organizations: @@ -449,6 +556,8 @@ definitions: description: 'example: 3fa85f64-5717-4562-b3fc-2c963f66afa6' format: uuid type: string + is_admin: + type: boolean is_disabled: type: boolean primary_email: @@ -516,6 +625,224 @@ paths: summary: Get JWKS tags: - Auth + /admin/archer/jobs: + get: + consumes: + - application/json + description: Paginated background jobs with optional filters. Search `q` may + match id, type, error, payload (implementation-dependent). + operationId: AdminListArcherJobs + parameters: + - description: Filter by status + enum: + - queued + - running + - succeeded + - failed + - canceled + - retrying + - scheduled + in: query + name: status + type: string + - description: Filter by queue name / worker name + in: query + name: queue + type: string + - description: Free-text search + in: query + name: q + type: string + - default: 1 + description: Page number + in: query + name: page + type: integer + - default: 25 + description: Items per page + in: query + maximum: 100 + minimum: 1 + name: page_size + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dto.PageJob' + "401": + description: Unauthorized + schema: + type: string + "403": + description: forbidden + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: List Archer jobs (admin) + tags: + - ArcherAdmin + post: + consumes: + - application/json + description: Create a job immediately or schedule it for the future via `run_at`. + operationId: AdminEnqueueArcherJob + parameters: + - description: Job parameters + in: body + name: body + required: true + schema: + $ref: '#/definitions/dto.EnqueueRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dto.Job' + "400": + description: invalid json or missing fields + schema: + type: string + "401": + description: Unauthorized + schema: + type: string + "403": + description: forbidden + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: Enqueue a new Archer job (admin) + tags: + - ArcherAdmin + /admin/archer/jobs/{id}/cancel: + post: + consumes: + - application/json + description: Set job status to canceled if cancellable. For running jobs, this + only affects future picks; wire to Archer if you need active kill. + operationId: AdminCancelArcherJob + parameters: + - description: Job ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dto.Job' + "400": + description: invalid job or not cancellable + schema: + type: string + "401": + description: Unauthorized + schema: + type: string + "403": + description: forbidden + schema: + type: string + "404": + description: not found + schema: + type: string + security: + - BearerAuth: [] + summary: Cancel an Archer job (admin) + tags: + - ArcherAdmin + /admin/archer/jobs/{id}/retry: + post: + consumes: + - application/json + description: Marks the job retriable (DB flip). Swap this for an Archer admin + call if you expose one. + operationId: AdminRetryArcherJob + parameters: + - description: Job ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dto.Job' + "400": + description: invalid job or not eligible + schema: + type: string + "401": + description: Unauthorized + schema: + type: string + "403": + description: forbidden + schema: + type: string + "404": + description: not found + schema: + type: string + security: + - BearerAuth: [] + summary: Retry a failed/canceled Archer job (admin) + tags: + - ArcherAdmin + /admin/archer/queues: + get: + consumes: + - application/json + description: Summary metrics per queue (pending, running, failed, scheduled). + operationId: AdminListArcherQueues + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/dto.QueueInfo' + type: array + "401": + description: Unauthorized + schema: + type: string + "403": + description: forbidden + schema: + type: string + "500": + description: internal error + schema: + type: string + security: + - BearerAuth: [] + summary: List Archer queues (admin) + tags: + - ArcherAdmin /annotations: get: consumes: @@ -569,7 +896,98 @@ paths: summary: List annotations (org scoped) tags: - Annotations + post: + consumes: + - application/json + description: Creates an annotation. + operationId: CreateAnnotation + parameters: + - description: Organization UUID + in: header + name: X-Org-ID + type: string + - description: Annotation payload + in: body + name: body + required: true + schema: + $ref: '#/definitions/dto.CreateAnnotationRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/dto.AnnotationResponse' + "400": + description: invalid json / missing fields + schema: + type: string + "401": + description: Unauthorized + schema: + type: string + "403": + description: organization required + schema: + type: string + "500": + description: create failed + schema: + type: string + security: + - BearerAuth: [] + - OrgKeyAuth: [] + - OrgSecretAuth: [] + summary: Create annotation (org scoped) + tags: + - Annotations /annotations/{id}: + delete: + consumes: + - application/json + description: Permanently deletes the annotation. + operationId: DeleteAnnotation + parameters: + - description: Organization UUID + in: header + name: X-Org-ID + type: string + - description: Annotation ID (UUID) + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + schema: + type: string + "400": + description: invalid id + schema: + type: string + "401": + description: Unauthorized + schema: + type: string + "403": + description: organization required + schema: + type: string + "500": + description: delete failed + schema: + type: string + security: + - BearerAuth: [] + - OrgKeyAuth: [] + - OrgSecretAuth: [] + summary: Delete annotation (org scoped) + tags: + - Annotations get: consumes: - application/json @@ -586,10 +1004,6 @@ paths: name: id required: true type: string - - description: 'Optional: node_pools' - in: query - name: include - type: string produces: - application/json responses: @@ -624,6 +1038,61 @@ paths: summary: Get annotation by ID (org scoped) tags: - Annotations + patch: + consumes: + - application/json + description: Partially update annotation fields. + operationId: UpdateAnnotation + parameters: + - description: Organization UUID + in: header + name: X-Org-ID + type: string + - description: Annotation ID (UUID) + in: path + name: id + required: true + type: string + - description: Fields to update + in: body + name: body + required: true + schema: + $ref: '#/definitions/dto.UpdateAnnotationRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dto.AnnotationResponse' + "400": + description: invalid id / invalid json + schema: + type: string + "401": + description: Unauthorized + schema: + type: string + "403": + description: organization required + schema: + type: string + "404": + description: not found + schema: + type: string + "500": + description: update failed + schema: + type: string + security: + - BearerAuth: [] + - OrgKeyAuth: [] + - OrgSecretAuth: [] + summary: Update annotation (org scoped) + tags: + - Annotations /auth/{provider}/callback: get: operationId: AuthCallback diff --git a/internal/api/httpmiddleware/platform_admin.go b/internal/api/httpmiddleware/platform_admin.go new file mode 100644 index 0000000..c05070c --- /dev/null +++ b/internal/api/httpmiddleware/platform_admin.go @@ -0,0 +1,45 @@ +package httpmiddleware + +import ( + "net/http" + + "github.com/glueops/autoglue/internal/utils" +) + +// RequireAuthenticatedUser ensures a user principal is present (i.e. not an org/machine key). +func RequireAuthenticatedUser() func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if user, ok := UserFrom(r.Context()); !ok || user == nil { + // No user in context -> probably org/machine principal, or unauthenticated + utils.WriteError(w, http.StatusUnauthorized, "unauthorized", "user principal required") + return + } + next.ServeHTTP(w, r) + }) + } +} + +// RequirePlatformAdmin requires a user principal with IsAdmin=true. +// This is platform-wide (non-org) admin and does NOT depend on org roles. +func RequirePlatformAdmin() func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + user, ok := UserFrom(r.Context()) + if !ok || user == nil { + utils.WriteError(w, http.StatusUnauthorized, "unauthorized", "user principal required") + return + } + if !user.IsAdmin { + utils.WriteError(w, http.StatusForbidden, "forbidden", "platform admin required") + return + } + next.ServeHTTP(w, r) + }) + } +} + +// RequireUserAdmin is an alias for RequirePlatformAdmin for readability at call sites. +func RequireUserAdmin() func(http.Handler) http.Handler { + return RequirePlatformAdmin() +} diff --git a/internal/api/routes.go b/internal/api/routes.go index fe1d25c..12d5d5d 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -9,6 +9,7 @@ import ( "github.com/glueops/autoglue/docs" "github.com/glueops/autoglue/internal/api/httpmiddleware" + "github.com/glueops/autoglue/internal/bg" "github.com/glueops/autoglue/internal/config" "github.com/glueops/autoglue/internal/handlers" "github.com/glueops/autoglue/internal/web" @@ -26,7 +27,7 @@ import ( httpSwagger "github.com/swaggo/http-swagger/v2" ) -func NewRouter(db *gorm.DB) http.Handler { +func NewRouter(db *gorm.DB, jobs *bg.Jobs) http.Handler { zerolog.TimeFieldFormat = time.RFC3339 l := log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "15:04:05"}) @@ -78,6 +79,17 @@ func NewRouter(db *gorm.DB) http.Handler { a.Post("/logout", handlers.Logout(db)) }) + v1.Route("/admin/archer", func(a chi.Router) { + a.Use(authUser) + a.Use(httpmiddleware.RequirePlatformAdmin()) + + a.Get("/jobs", handlers.AdminListArcherJobs(db)) + a.Post("/jobs", handlers.AdminEnqueueArcherJob(db, jobs)) + a.Post("/jobs/{id}/retry", handlers.AdminRetryArcherJob(db)) + a.Post("/jobs/{id}/cancel", handlers.AdminCancelArcherJob(db)) + a.Get("/queues", handlers.AdminListArcherQueues(db)) + }) + v1.Route("/me", func(me chi.Router) { me.Use(authUser) @@ -139,13 +151,22 @@ func NewRouter(db *gorm.DB) http.Handler { s.Delete("/{id}", handlers.DeleteTaint(db)) }) - v1.Route("/labels", func(s chi.Router) { - s.Use(authOrg) - s.Get("/", handlers.ListLabels(db)) - s.Post("/", handlers.CreateLabel(db)) - s.Get("/{id}", handlers.GetLabel(db)) - s.Patch("/{id}", handlers.UpdateLabel(db)) - s.Delete("/{id}", handlers.DeleteLabel(db)) + v1.Route("/labels", func(l chi.Router) { + l.Use(authOrg) + l.Get("/", handlers.ListLabels(db)) + l.Post("/", handlers.CreateLabel(db)) + l.Get("/{id}", handlers.GetLabel(db)) + l.Patch("/{id}", handlers.UpdateLabel(db)) + l.Delete("/{id}", handlers.DeleteLabel(db)) + }) + + v1.Route("/annotations", func(a chi.Router) { + a.Use(authOrg) + a.Get("/", handlers.ListAnnotations(db)) + a.Post("/", handlers.CreateAnnotation(db)) + a.Get("/{id}", handlers.GetAnnotation(db)) + a.Patch("/{id}", handlers.UpdateAnnotation(db)) + a.Delete("/{id}", handlers.DeleteAnnotation(db)) }) }) }) diff --git a/internal/bg/bastion.go b/internal/bg/bastion.go index eed43ce..5c6d76d 100644 --- a/internal/bg/bastion.go +++ b/internal/bg/bastion.go @@ -53,7 +53,7 @@ func BastionBootstrapWorker(db *gorm.DB) archer.WorkerFn { return nil, err } - log.Printf("[bastion] level=INFO job=%s step=start count=%d", jobID, len(servers)) + // log.Printf("[bastion] level=INFO job=%s step=start count=%d", jobID, len(servers)) proc, ok, fail := 0, 0, 0 var failedIDs []uuid.UUID @@ -63,7 +63,7 @@ func BastionBootstrapWorker(db *gorm.DB) archer.WorkerFn { for i := range servers { s := &servers[i] - hostStart := time.Now() + // hostStart := time.Now() proc++ // 1) Defensive IP check @@ -133,8 +133,8 @@ func BastionBootstrapWorker(db *gorm.DB) archer.WorkerFn { } ok++ - logHostInfo(jobID, s, "done", "host completed", - "elapsed_ms", time.Since(hostStart).Milliseconds()) + // logHostInfo(jobID, s, "done", "host completed", + // "elapsed_ms", time.Since(hostStart).Milliseconds()) } res := BastionBootstrapResult{ @@ -147,8 +147,8 @@ func BastionBootstrapWorker(db *gorm.DB) archer.WorkerFn { Failures: failures, } - log.Printf("[bastion] level=INFO job=%s step=finish processed=%d ready=%d failed=%d elapsed_ms=%d", - jobID, proc, ok, fail, res.ElapsedMs) + // log.Printf("[bastion] level=INFO job=%s step=finish processed=%d ready=%d failed=%d elapsed_ms=%d", + // jobID, proc, ok, fail, res.ElapsedMs) return res, nil } @@ -186,7 +186,6 @@ func logHostInfo(jobID string, s *models.Server, step, msg string, kv ...any) { // ----- SSH & command execution ----- -// returns combined stdout/stderr so caller can log it on error // returns combined stdout/stderr so caller can log it on error func sshInstallDockerWithOutput(ctx context.Context, host, user string, privateKeyPEM []byte) (string, error) { signer, err := ssh.ParsePrivateKey(privateKeyPEM) diff --git a/internal/handlers/annotations.go b/internal/handlers/annotations.go index 5389f20..b2ebca7 100644 --- a/internal/handlers/annotations.go +++ b/internal/handlers/annotations.go @@ -1,11 +1,13 @@ package handlers import ( + "encoding/json" "errors" "net/http" "strings" "github.com/glueops/autoglue/internal/api/httpmiddleware" + "github.com/glueops/autoglue/internal/common" "github.com/glueops/autoglue/internal/handlers/dto" "github.com/glueops/autoglue/internal/models" "github.com/glueops/autoglue/internal/utils" @@ -71,7 +73,6 @@ func ListAnnotations(db *gorm.DB) http.HandlerFunc { // @Produce json // @Param X-Org-ID header string false "Organization UUID" // @Param id path string true "Annotation ID (UUID)" -// @Param include query string false "Optional: node_pools" // @Success 200 {object} dto.AnnotationResponse // @Failure 400 {string} string "invalid id" // @Failure 401 {string} string "Unauthorized" @@ -108,3 +109,174 @@ func GetAnnotation(db *gorm.DB) http.HandlerFunc { utils.WriteJSON(w, http.StatusOK, out) } } + +// CreateAnnotation godoc +// @ID CreateAnnotation +// @Summary Create annotation (org scoped) +// @Description Creates an annotation. +// @Tags Annotations +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param body body dto.CreateAnnotationRequest true "Annotation payload" +// @Success 201 {object} dto.AnnotationResponse +// @Failure 400 {string} string "invalid json / missing fields" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "create failed" +// @Router /annotations [post] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth +func CreateAnnotation(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) + if !ok { + utils.WriteError(w, http.StatusForbidden, "org_required", "specify X-Org-ID") + return + } + + var req dto.CreateAnnotationRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_request", "bad request") + return + } + + req.Key = strings.TrimSpace(req.Key) + req.Value = strings.TrimSpace(req.Value) + + if req.Key == "" || req.Value == "" { + utils.WriteError(w, http.StatusBadRequest, "bad_request", "missing key/value") + return + } + + a := models.Annotation{ + AuditFields: common.AuditFields{OrganizationID: orgID}, + Key: req.Key, + Value: req.Value, + } + + if err := db.Create(&a).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + out := dto.AnnotationResponse{ + AuditFields: a.AuditFields, + Key: a.Key, + Value: a.Value, + } + utils.WriteJSON(w, http.StatusCreated, out) + } +} + +// UpdateAnnotation godoc +// @ID UpdateAnnotation +// @Summary Update annotation (org scoped) +// @Description Partially update annotation fields. +// @Tags Annotations +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Annotation ID (UUID)" +// @Param body body dto.UpdateAnnotationRequest true "Fields to update" +// @Success 200 {object} dto.AnnotationResponse +// @Failure 400 {string} string "invalid id / invalid json" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "update failed" +// @Router /annotations/{id} [patch] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth +func UpdateAnnotation(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) + if !ok { + utils.WriteError(w, http.StatusForbidden, "org_required", "specify X-Org-ID") + return + } + + id, err := uuid.Parse(chi.URLParam(r, "id")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_request", "bad request") + return + } + + var a models.Annotation + if err := db.Where("id = ? AND organization_id = ?", id, orgID).First(&a).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + utils.WriteError(w, http.StatusNotFound, "not_found", "not_found") + return + } + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + var req dto.UpdateAnnotationRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_request", "bad request") + return + } + + if req.Key != nil { + a.Key = strings.TrimSpace(*req.Key) + } + if req.Value != nil { + a.Value = strings.TrimSpace(*req.Value) + } + + if err := db.Save(&a).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + out := dto.AnnotationResponse{ + AuditFields: a.AuditFields, + Key: a.Key, + Value: a.Value, + } + utils.WriteJSON(w, http.StatusOK, out) + } +} + +// DeleteAnnotation godoc +// @ID DeleteAnnotation +// @Summary Delete annotation (org scoped) +// @Description Permanently deletes the annotation. +// @Tags Annotations +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Annotation ID (UUID)" +// @Success 204 {string} string "No Content" +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "delete failed" +// @Router /annotations/{id} [delete] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth +func DeleteAnnotation(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) + if !ok { + utils.WriteError(w, http.StatusForbidden, "org_required", "specify X-Org-ID") + return + } + + id, err := uuid.Parse(chi.URLParam(r, "id")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_request", "bad request") + return + } + + if err := db.Where("id = ? AND organization_id = ?", id, orgID).Delete(&models.Annotation{}).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + w.WriteHeader(http.StatusNoContent) + } +} diff --git a/internal/handlers/dto/jobs.go b/internal/handlers/dto/jobs.go new file mode 100644 index 0000000..55164df --- /dev/null +++ b/internal/handlers/dto/jobs.go @@ -0,0 +1,62 @@ +package dto + +import ( + "encoding/json" + "time" +) + +type JobStatus string + +const ( + StatusQueued JobStatus = "queued" + StatusRunning JobStatus = "running" + StatusSucceeded JobStatus = "succeeded" + StatusFailed JobStatus = "failed" + StatusCanceled JobStatus = "canceled" + StatusRetrying JobStatus = "retrying" + StatusScheduled JobStatus = "scheduled" +) + +// Job represents a background job managed by Archer. +// swagger:model Job +type Job struct { + ID string `json:"id" example:"01HF7SZK8Z8WG1M3J7S2Z8M2N6"` + Type string `json:"type" example:"email.send"` + Queue string `json:"queue" example:"default"` + Status JobStatus `json:"status" example:"queued" enums:"queued|running|succeeded|failed|canceled|retrying|scheduled"` + Attempts int `json:"attempts" example:"0"` + MaxAttempts int `json:"max_attempts,omitempty" example:"3"` + CreatedAt time.Time `json:"created_at" example:"2025-11-04T09:30:00Z"` + UpdatedAt *time.Time `json:"updated_at,omitempty" example:"2025-11-04T09:30:00Z"` + LastError *string `json:"last_error,omitempty" example:"error message"` + RunAt *time.Time `json:"run_at,omitempty" example:"2025-11-04T09:30:00Z"` + Payload any `json:"payload,omitempty"` +} + +// QueueInfo holds queue-level counts. +// swagger:model QueueInfo +type QueueInfo struct { + Name string `json:"name" example:"default"` + Pending int `json:"pending" example:"42"` + Running int `json:"running" example:"3"` + Failed int `json:"failed" example:"5"` + Scheduled int `json:"scheduled" example:"7"` +} + +// PageJob is a concrete paginated response for Job (generics not supported by swag). +// swagger:model PageJob +type PageJob struct { + Items []Job `json:"items"` + Total int `json:"total" example:"120"` + Page int `json:"page" example:"1"` + PageSize int `json:"page_size" example:"25"` +} + +// EnqueueRequest is the POST body for creating a job. +// swagger:model EnqueueRequest +type EnqueueRequest struct { + Queue string `json:"queue" example:"default"` + Type string `json:"type" example:"email.send"` + Payload json.RawMessage `json:"payload"` + RunAt *time.Time `json:"run_at" example:"2025-11-05T08:00:00Z"` +} diff --git a/internal/handlers/jobs.go b/internal/handlers/jobs.go new file mode 100644 index 0000000..d4c4c9a --- /dev/null +++ b/internal/handlers/jobs.go @@ -0,0 +1,383 @@ +package handlers + +import ( + "context" + "encoding/json" + "net/http" + "strconv" + "strings" + "time" + + "github.com/dyaksa/archer" + "github.com/glueops/autoglue/internal/bg" + "github.com/glueops/autoglue/internal/handlers/dto" + "github.com/glueops/autoglue/internal/models" + "github.com/glueops/autoglue/internal/utils" + "github.com/go-chi/chi/v5" + "github.com/google/uuid" + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +// AdminListArcherJobs godoc +// @ID AdminListArcherJobs +// @Summary List Archer jobs (admin) +// @Description Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent). +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Param status query string false "Filter by status" Enums(queued,running,succeeded,failed,canceled,retrying,scheduled) +// @Param queue query string false "Filter by queue name / worker name" +// @Param q query string false "Free-text search" +// @Param page query int false "Page number" default(1) +// @Param page_size query int false "Items per page" minimum(1) maximum(100) default(25) +// @Success 200 {object} dto.PageJob +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 500 {string} string "internal error" +// @Router /admin/archer/jobs [get] +// @Security BearerAuth +func AdminListArcherJobs(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + status := strings.TrimSpace(r.URL.Query().Get("status")) + queue := strings.TrimSpace(r.URL.Query().Get("queue")) + q := strings.TrimSpace(r.URL.Query().Get("q")) + page := atoiDefault(r.URL.Query().Get("page"), 1) + size := clamp(atoiDefault(r.URL.Query().Get("page_size"), 25), 1, 100) + + base := db.Model(&models.Job{}) + if status != "" { + base = base.Where("status = ?", status) + } + if queue != "" { + base = base.Where("queue_name = ?", queue) + } + if q != "" { + like := "%" + q + "%" + base = base.Where( + db.Where("id ILIKE ?", like). + Or("queue_name ILIKE ?", like). + Or("COALESCE(last_error,'') ILIKE ?", like). + Or("CAST(arguments AS TEXT) ILIKE ?", like), + ) + } + + var total int64 + if err := base.Count(&total).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error()) + return + } + + var rows []models.Job + offset := (page - 1) * size + if err := base.Order("created_at DESC").Limit(size).Offset(offset).Find(&rows).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error()) + return + } + + items := make([]dto.Job, 0, len(rows)) + for _, m := range rows { + items = append(items, mapModelJobToDTO(m)) + } + + utils.WriteJSON(w, http.StatusOK, dto.PageJob{ + Items: items, + Total: int(total), + Page: page, + PageSize: size, + }) + } +} + +// AdminEnqueueArcherJob godoc +// @ID AdminEnqueueArcherJob +// @Summary Enqueue a new Archer job (admin) +// @Description Create a job immediately or schedule it for the future via `run_at`. +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Param body body dto.EnqueueRequest true "Job parameters" +// @Success 200 {object} dto.Job +// @Failure 400 {string} string "invalid json or missing fields" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 500 {string} string "internal error" +// @Router /admin/archer/jobs [post] +// @Security BearerAuth +func AdminEnqueueArcherJob(db *gorm.DB, jobs *bg.Jobs) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var in dto.EnqueueRequest + if err := json.NewDecoder(r.Body).Decode(&in); err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_request", "invalid json") + return + } + in.Queue = strings.TrimSpace(in.Queue) + in.Type = strings.TrimSpace(in.Type) + if in.Queue == "" || in.Type == "" { + utils.WriteError(w, http.StatusBadRequest, "bad_request", "queue and type are required") + return + } + + // Parse payload into generic 'args' for Archer. + var args any + if len(in.Payload) > 0 && string(in.Payload) != "null" { + if err := json.Unmarshal(in.Payload, &args); err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_request", "payload must be valid JSON") + return + } + } + + id := uuid.NewString() + + opts := []archer.FnOptions{ + archer.WithMaxRetries(0), // adjust or expose in request if needed + } + if in.RunAt != nil { + opts = append(opts, archer.WithScheduleTime(*in.RunAt)) + } + + // Schedule with Archer (queue == worker name). + if _, err := jobs.Enqueue(context.Background(), id, in.Queue, args, opts...); err != nil { + utils.WriteError(w, http.StatusInternalServerError, "enqueue_failed", err.Error()) + return + } + + // Read back the just-created row. + var m models.Job + if err := db.First(&m, "id = ?", id).Error; err != nil { + // Fallback: return a synthesized job if row not visible yet. + now := time.Now() + out := dto.Job{ + ID: id, + Type: in.Type, + Queue: in.Queue, + Status: dto.StatusQueued, + Attempts: 0, + MaxAttempts: 0, + CreatedAt: now, + UpdatedAt: &now, + RunAt: in.RunAt, + Payload: args, + } + utils.WriteJSON(w, http.StatusOK, out) + return + } + + utils.WriteJSON(w, http.StatusOK, mapModelJobToDTO(m)) + } +} + +// AdminRetryArcherJob godoc +// @ID AdminRetryArcherJob +// @Summary Retry a failed/canceled Archer job (admin) +// @Description Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one. +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Param id path string true "Job ID" +// @Success 200 {object} dto.Job +// @Failure 400 {string} string "invalid job or not eligible" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 404 {string} string "not found" +// @Router /admin/archer/jobs/{id}/retry [post] +// @Security BearerAuth +func AdminRetryArcherJob(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + var m models.Job + if err := db.Clauses(clause.Locking{Strength: "UPDATE"}).First(&m, "id = ?", id).Error; err != nil { + if err == gorm.ErrRecordNotFound { + utils.WriteError(w, http.StatusNotFound, "not_found", "job not found") + return + } + utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error()) + return + } + + // Only allow retry from failed/canceled (adjust as you see fit). + if m.Status != string(dto.StatusFailed) && m.Status != string(dto.StatusCanceled) { + utils.WriteError(w, http.StatusBadRequest, "not_eligible", "job is not failed/canceled") + return + } + + // Reset to queued; clear started_at; bump updated_at. + now := time.Now() + if err := db.Model(&m).Updates(map[string]any{ + "status": string(dto.StatusQueued), + "started_at": nil, + "updated_at": now, + }).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error()) + return + } + + // Re-read and return. + if err := db.First(&m, "id = ?", id).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error()) + return + } + utils.WriteJSON(w, http.StatusOK, mapModelJobToDTO(m)) + } +} + +// AdminCancelArcherJob godoc +// @ID AdminCancelArcherJob +// @Summary Cancel an Archer job (admin) +// @Description Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill. +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Param id path string true "Job ID" +// @Success 200 {object} dto.Job +// @Failure 400 {string} string "invalid job or not cancellable" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 404 {string} string "not found" +// @Router /admin/archer/jobs/{id}/cancel [post] +// @Security BearerAuth +func AdminCancelArcherJob(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + var m models.Job + if err := db.Clauses(clause.Locking{Strength: "UPDATE"}).First(&m, "id = ?", id).Error; err != nil { + if err == gorm.ErrRecordNotFound { + utils.WriteError(w, http.StatusNotFound, "not_found", "job not found") + return + } + utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error()) + return + } + + // If already finished, bail. + switch m.Status { + case string(dto.StatusSucceeded), string(dto.StatusCanceled): + utils.WriteError(w, http.StatusBadRequest, "not_cancellable", "job already finished") + return + } + + now := time.Now() + if err := db.Model(&m).Updates(map[string]any{ + "status": string(dto.StatusCanceled), + "updated_at": now, + }).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error()) + return + } + + if err := db.First(&m, "id = ?", id).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error()) + return + } + utils.WriteJSON(w, http.StatusOK, mapModelJobToDTO(m)) + } +} + +// AdminListArcherQueues godoc +// @ID AdminListArcherQueues +// @Summary List Archer queues (admin) +// @Description Summary metrics per queue (pending, running, failed, scheduled). +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Success 200 {array} dto.QueueInfo +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 500 {string} string "internal error" +// @Router /admin/archer/queues [get] +// @Security BearerAuth +func AdminListArcherQueues(db *gorm.DB) http.HandlerFunc { + type row struct { + QueueName string + Pending int + Running int + Failed int + Scheduled int + } + + return func(w http.ResponseWriter, r *http.Request) { + var rows []row + // Use filtered aggregate; adjust status values if your Archer differs. + if err := db. + Raw(` + SELECT + queue_name, + COUNT(*) FILTER (WHERE status = 'queued') AS pending, + COUNT(*) FILTER (WHERE status = 'running') AS running, + COUNT(*) FILTER (WHERE status = 'failed') AS failed, + COUNT(*) FILTER (WHERE status = 'scheduled') AS scheduled + FROM jobs + GROUP BY queue_name + ORDER BY queue_name ASC + `).Scan(&rows).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error()) + return + } + + out := make([]dto.QueueInfo, 0, len(rows)) + for _, r := range rows { + out = append(out, dto.QueueInfo{ + Name: r.QueueName, + Pending: r.Pending, + Running: r.Running, + Failed: r.Failed, + Scheduled: r.Scheduled, + }) + } + + utils.WriteJSON(w, http.StatusOK, out) + } +} + +// Helpers +func atoiDefault(s string, def int) int { + if s == "" { + return def + } + if n, err := strconv.Atoi(s); err == nil { + return n + } + return def +} +func clamp(n, lo, hi int) int { + if n < lo { + return lo + } + if n > hi { + return hi + } + return n +} + +func mapModelJobToDTO(m models.Job) dto.Job { + var payload any + if len(m.Arguments) > 0 { + _ = json.Unmarshal([]byte(m.Arguments), &payload) + } + + var updated *time.Time + if !m.UpdatedAt.IsZero() { + updated = &m.UpdatedAt + } + + var runAt *time.Time + if !m.ScheduledAt.IsZero() { + rt := m.ScheduledAt + runAt = &rt + } + + return dto.Job{ + ID: m.ID, + // If you distinguish between queue and type elsewhere, set Type accordingly. + Type: m.QueueName, + Queue: m.QueueName, + Status: dto.JobStatus(m.Status), + Attempts: m.RetryCount, + MaxAttempts: m.MaxRetry, + CreatedAt: m.CreatedAt, + UpdatedAt: updated, + LastError: m.LastError, + RunAt: runAt, + Payload: payload, + } +} diff --git a/internal/handlers/me.go b/internal/handlers/me.go index e6a9f2e..16a6a3b 100644 --- a/internal/handlers/me.go +++ b/internal/handlers/me.go @@ -40,7 +40,7 @@ func GetMe(db *gorm.DB) http.HandlerFunc { } var emails []models.UserEmail - _ = db.Where("user_id = ?", user.ID).Order("is_primary desc, created_at asc").Find(&emails).Error + _ = db.Preload("User").Where("user_id = ?", user.ID).Order("is_primary desc, created_at asc").Find(&emails).Error var orgs []models.Organization { diff --git a/internal/models/user.go b/internal/models/user.go index 8273cc5..af9ffae 100644 --- a/internal/models/user.go +++ b/internal/models/user.go @@ -13,6 +13,7 @@ type User struct { PrimaryEmail *string `json:"primary_email,omitempty"` AvatarURL *string `json:"avatar_url,omitempty"` IsDisabled bool `json:"is_disabled"` + IsAdmin bool `gorm:"default:false" json:"is_admin"` CreatedAt time.Time `gorm:"column:created_at;not null;default:now()" json:"created_at" format:"date-time"` UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at;not null;default:now()" json:"updated_at" format:"date-time"` } diff --git a/sdk/go/.openapi-generator/FILES b/sdk/go/.openapi-generator/FILES index cac0353..1edc0f0 100644 --- a/sdk/go/.openapi-generator/FILES +++ b/sdk/go/.openapi-generator/FILES @@ -4,6 +4,7 @@ README.md api/openapi.yaml api_annotations.go +api_archer_admin.go api_auth.go api_health.go api_labels.go @@ -16,23 +17,30 @@ api_taints.go client.go configuration.go docs/AnnotationsAPI.md +docs/ArcherAdminAPI.md docs/AuthAPI.md docs/DtoAnnotationResponse.md docs/DtoAuthStartResponse.md +docs/DtoCreateAnnotationRequest.md docs/DtoCreateLabelRequest.md docs/DtoCreateSSHRequest.md docs/DtoCreateServerRequest.md docs/DtoCreateTaintRequest.md docs/DtoJWK.md docs/DtoJWKS.md +docs/DtoJob.md +docs/DtoJobStatus.md docs/DtoLabelResponse.md docs/DtoLogoutRequest.md +docs/DtoPageJob.md +docs/DtoQueueInfo.md docs/DtoRefreshRequest.md docs/DtoServerResponse.md docs/DtoSshResponse.md docs/DtoSshRevealResponse.md docs/DtoTaintResponse.md docs/DtoTokenPair.md +docs/DtoUpdateAnnotationRequest.md docs/DtoUpdateLabelRequest.md docs/DtoUpdateServerRequest.md docs/DtoUpdateTaintRequest.md @@ -65,20 +73,26 @@ go.mod go.sum model_dto_annotation_response.go model_dto_auth_start_response.go +model_dto_create_annotation_request.go model_dto_create_label_request.go model_dto_create_server_request.go model_dto_create_ssh_request.go model_dto_create_taint_request.go +model_dto_job.go +model_dto_job_status.go model_dto_jwk.go model_dto_jwks.go model_dto_label_response.go model_dto_logout_request.go +model_dto_page_job.go +model_dto_queue_info.go model_dto_refresh_request.go model_dto_server_response.go model_dto_ssh_response.go model_dto_ssh_reveal_response.go model_dto_taint_response.go model_dto_token_pair.go +model_dto_update_annotation_request.go model_dto_update_label_request.go model_dto_update_server_request.go model_dto_update_taint_request.go @@ -100,6 +114,7 @@ model_models_user_email.go model_utils_error_response.go response.go test/api_annotations_test.go +test/api_archer_admin_test.go test/api_auth_test.go test/api_health_test.go test/api_labels_test.go diff --git a/sdk/go/README.md b/sdk/go/README.md index 185eee6..7951cdc 100644 --- a/sdk/go/README.md +++ b/sdk/go/README.md @@ -78,8 +78,16 @@ All URIs are relative to *http://localhost:8080/api/v1* Class | Method | HTTP request | Description ------------ | ------------- | ------------- | ------------- +*AnnotationsAPI* | [**CreateAnnotation**](docs/AnnotationsAPI.md#createannotation) | **Post** /annotations | Create annotation (org scoped) +*AnnotationsAPI* | [**DeleteAnnotation**](docs/AnnotationsAPI.md#deleteannotation) | **Delete** /annotations/{id} | Delete annotation (org scoped) *AnnotationsAPI* | [**GetAnnotation**](docs/AnnotationsAPI.md#getannotation) | **Get** /annotations/{id} | Get annotation by ID (org scoped) *AnnotationsAPI* | [**ListAnnotations**](docs/AnnotationsAPI.md#listannotations) | **Get** /annotations | List annotations (org scoped) +*AnnotationsAPI* | [**UpdateAnnotation**](docs/AnnotationsAPI.md#updateannotation) | **Patch** /annotations/{id} | Update annotation (org scoped) +*ArcherAdminAPI* | [**AdminCancelArcherJob**](docs/ArcherAdminAPI.md#admincancelarcherjob) | **Post** /admin/archer/jobs/{id}/cancel | Cancel an Archer job (admin) +*ArcherAdminAPI* | [**AdminEnqueueArcherJob**](docs/ArcherAdminAPI.md#adminenqueuearcherjob) | **Post** /admin/archer/jobs | Enqueue a new Archer job (admin) +*ArcherAdminAPI* | [**AdminListArcherJobs**](docs/ArcherAdminAPI.md#adminlistarcherjobs) | **Get** /admin/archer/jobs | List Archer jobs (admin) +*ArcherAdminAPI* | [**AdminListArcherQueues**](docs/ArcherAdminAPI.md#adminlistarcherqueues) | **Get** /admin/archer/queues | List Archer queues (admin) +*ArcherAdminAPI* | [**AdminRetryArcherJob**](docs/ArcherAdminAPI.md#adminretryarcherjob) | **Post** /admin/archer/jobs/{id}/retry | Retry a failed/canceled Archer job (admin) *AuthAPI* | [**AuthCallback**](docs/AuthAPI.md#authcallback) | **Get** /auth/{provider}/callback | Handle social login callback *AuthAPI* | [**AuthStart**](docs/AuthAPI.md#authstart) | **Post** /auth/{provider}/start | Begin social login *AuthAPI* | [**GetJWKS**](docs/AuthAPI.md#getjwks) | **Get** /.well-known/jwks.json | Get JWKS @@ -128,20 +136,26 @@ Class | Method | HTTP request | Description - [DtoAnnotationResponse](docs/DtoAnnotationResponse.md) - [DtoAuthStartResponse](docs/DtoAuthStartResponse.md) + - [DtoCreateAnnotationRequest](docs/DtoCreateAnnotationRequest.md) - [DtoCreateLabelRequest](docs/DtoCreateLabelRequest.md) - [DtoCreateSSHRequest](docs/DtoCreateSSHRequest.md) - [DtoCreateServerRequest](docs/DtoCreateServerRequest.md) - [DtoCreateTaintRequest](docs/DtoCreateTaintRequest.md) - [DtoJWK](docs/DtoJWK.md) - [DtoJWKS](docs/DtoJWKS.md) + - [DtoJob](docs/DtoJob.md) + - [DtoJobStatus](docs/DtoJobStatus.md) - [DtoLabelResponse](docs/DtoLabelResponse.md) - [DtoLogoutRequest](docs/DtoLogoutRequest.md) + - [DtoPageJob](docs/DtoPageJob.md) + - [DtoQueueInfo](docs/DtoQueueInfo.md) - [DtoRefreshRequest](docs/DtoRefreshRequest.md) - [DtoServerResponse](docs/DtoServerResponse.md) - [DtoSshResponse](docs/DtoSshResponse.md) - [DtoSshRevealResponse](docs/DtoSshRevealResponse.md) - [DtoTaintResponse](docs/DtoTaintResponse.md) - [DtoTokenPair](docs/DtoTokenPair.md) + - [DtoUpdateAnnotationRequest](docs/DtoUpdateAnnotationRequest.md) - [DtoUpdateLabelRequest](docs/DtoUpdateLabelRequest.md) - [DtoUpdateServerRequest](docs/DtoUpdateServerRequest.md) - [DtoUpdateTaintRequest](docs/DtoUpdateTaintRequest.md) diff --git a/sdk/go/api/openapi.yaml b/sdk/go/api/openapi.yaml index 0f1604e..0d6cd2d 100644 --- a/sdk/go/api/openapi.yaml +++ b/sdk/go/api/openapi.yaml @@ -23,6 +23,258 @@ paths: summary: Get JWKS tags: - Auth + /admin/archer/jobs: + get: + description: "Paginated background jobs with optional filters. Search `q` may\ + \ match id, type, error, payload (implementation-dependent)." + operationId: AdminListArcherJobs + parameters: + - description: Filter by status + in: query + name: status + schema: + enum: + - queued + - running + - succeeded + - failed + - canceled + - retrying + - scheduled + type: string + - description: Filter by queue name / worker name + in: query + name: queue + schema: + type: string + - description: Free-text search + in: query + name: q + schema: + type: string + - description: Page number + in: query + name: page + schema: + default: 1 + type: integer + - description: Items per page + in: query + name: page_size + schema: + default: 25 + maximum: 100 + minimum: 1 + type: integer + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/dto.PageJob" + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: forbidden + "500": + content: + application/json: + schema: + type: string + description: internal error + security: + - BearerAuth: [] + summary: List Archer jobs (admin) + tags: + - ArcherAdmin + post: + description: Create a job immediately or schedule it for the future via `run_at`. + operationId: AdminEnqueueArcherJob + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/dto.EnqueueRequest" + description: Job parameters + required: true + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/dto.Job" + description: OK + "400": + content: + application/json: + schema: + type: string + description: invalid json or missing fields + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: forbidden + "500": + content: + application/json: + schema: + type: string + description: internal error + security: + - BearerAuth: [] + summary: Enqueue a new Archer job (admin) + tags: + - ArcherAdmin + x-codegen-request-body-name: body + /admin/archer/jobs/{id}/cancel: + post: + description: "Set job status to canceled if cancellable. For running jobs, this\ + \ only affects future picks; wire to Archer if you need active kill." + operationId: AdminCancelArcherJob + parameters: + - description: Job ID + in: path + name: id + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/dto.Job" + description: OK + "400": + content: + application/json: + schema: + type: string + description: invalid job or not cancellable + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: forbidden + "404": + content: + application/json: + schema: + type: string + description: not found + security: + - BearerAuth: [] + summary: Cancel an Archer job (admin) + tags: + - ArcherAdmin + /admin/archer/jobs/{id}/retry: + post: + description: Marks the job retriable (DB flip). Swap this for an Archer admin + call if you expose one. + operationId: AdminRetryArcherJob + parameters: + - description: Job ID + in: path + name: id + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/dto.Job" + description: OK + "400": + content: + application/json: + schema: + type: string + description: invalid job or not eligible + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: forbidden + "404": + content: + application/json: + schema: + type: string + description: not found + security: + - BearerAuth: [] + summary: Retry a failed/canceled Archer job (admin) + tags: + - ArcherAdmin + /admin/archer/queues: + get: + description: "Summary metrics per queue (pending, running, failed, scheduled)." + operationId: AdminListArcherQueues + responses: + "200": + content: + application/json: + schema: + items: + $ref: "#/components/schemas/dto.QueueInfo" + type: array + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: forbidden + "500": + content: + application/json: + schema: + type: string + description: internal error + security: + - BearerAuth: [] + summary: List Archer queues (admin) + tags: + - ArcherAdmin /annotations: get: description: "Returns annotations for the organization in X-Org-ID. Filters:\ @@ -84,7 +336,115 @@ paths: summary: List annotations (org scoped) tags: - Annotations + post: + description: Creates an annotation. + operationId: CreateAnnotation + parameters: + - description: Organization UUID + in: header + name: X-Org-ID + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/dto.CreateAnnotationRequest" + description: Annotation payload + required: true + responses: + "201": + content: + application/json: + schema: + $ref: "#/components/schemas/dto.AnnotationResponse" + description: Created + "400": + content: + application/json: + schema: + type: string + description: invalid json / missing fields + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: organization required + "500": + content: + application/json: + schema: + type: string + description: create failed + security: + - BearerAuth: [] + - OrgKeyAuth: [] + - OrgSecretAuth: [] + summary: Create annotation (org scoped) + tags: + - Annotations + x-codegen-request-body-name: body /annotations/{id}: + delete: + description: Permanently deletes the annotation. + operationId: DeleteAnnotation + parameters: + - description: Organization UUID + in: header + name: X-Org-ID + schema: + type: string + - description: Annotation ID (UUID) + in: path + name: id + required: true + schema: + type: string + responses: + "204": + content: + application/json: + schema: + type: string + description: No Content + "400": + content: + application/json: + schema: + type: string + description: invalid id + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: organization required + "500": + content: + application/json: + schema: + type: string + description: delete failed + security: + - BearerAuth: [] + - OrgKeyAuth: [] + - OrgSecretAuth: [] + summary: Delete annotation (org scoped) + tags: + - Annotations get: description: Returns one annotation. Add `include=node_pools` to include node pools. @@ -101,11 +461,6 @@ paths: required: true schema: type: string - - description: "Optional: node_pools" - in: query - name: include - schema: - type: string responses: "200": content: @@ -150,6 +505,73 @@ paths: summary: Get annotation by ID (org scoped) tags: - Annotations + patch: + description: Partially update annotation fields. + operationId: UpdateAnnotation + parameters: + - description: Organization UUID + in: header + name: X-Org-ID + schema: + type: string + - description: Annotation ID (UUID) + in: path + name: id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/dto.UpdateAnnotationRequest" + description: Fields to update + required: true + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/dto.AnnotationResponse" + description: OK + "400": + content: + application/json: + schema: + type: string + description: invalid id / invalid json + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: organization required + "404": + content: + application/json: + schema: + type: string + description: not found + "500": + content: + application/json: + schema: + type: string + description: update failed + security: + - BearerAuth: [] + - OrgKeyAuth: [] + - OrgSecretAuth: [] + summary: Update annotation (org scoped) + tags: + - Annotations + x-codegen-request-body-name: body /auth/logout: post: operationId: Logout @@ -1911,6 +2333,13 @@ components: example: https://accounts.google.com/o/oauth2/v2/auth?client_id=... type: string type: object + dto.CreateAnnotationRequest: + properties: + key: + type: string + value: + type: string + type: object dto.CreateLabelRequest: properties: key: @@ -1960,6 +2389,8 @@ components: value: type: string type: object + dto.EnqueueRequest: + type: object dto.JWK: example: kty: RSA @@ -2013,6 +2444,76 @@ components: $ref: "#/components/schemas/dto.JWK" type: array type: object + dto.Job: + example: + updated_at: updated_at + payload: "{}" + max_attempts: 6 + created_at: created_at + id: id + last_error: last_error + run_at: run_at + type: type + queue: queue + attempts: 0 + status: "{}" + properties: + attempts: + description: "example: 0" + type: integer + created_at: + description: "example: 2025-11-04T09:30:00Z" + type: string + id: + description: "example: 01HF7SZK8Z8WG1M3J7S2Z8M2N6" + type: string + last_error: + description: "example: dial tcp: i/o timeout" + type: string + max_attempts: + description: "example: 3" + type: integer + payload: + description: arbitrary JSON payload + type: object + queue: + description: "example: default" + type: string + run_at: + description: "example: 2025-11-05T08:00:00Z" + type: string + status: + allOf: + - $ref: "#/components/schemas/dto.JobStatus" + description: |- + enum: queued,running,succeeded,failed,canceled,retrying,scheduled + example: queued + type: object + type: + description: "example: email.send" + type: string + updated_at: + description: "example: 2025-11-04T09:31:00Z" + type: string + type: object + dto.JobStatus: + enum: + - queued + - running + - succeeded + - failed + - canceled + - retrying + - scheduled + type: string + x-enum-varnames: + - StatusQueued + - StatusRunning + - StatusSucceeded + - StatusFailed + - StatusCanceled + - StatusRetrying + - StatusScheduled dto.LabelResponse: example: updated_at: updated_at @@ -2041,6 +2542,73 @@ components: example: m0l9o8rT3t0V8d3eFf... type: string type: object + dto.PageJob: + example: + total: 5 + page: 1 + items: + - updated_at: updated_at + payload: "{}" + max_attempts: 6 + created_at: created_at + id: id + last_error: last_error + run_at: run_at + type: type + queue: queue + attempts: 0 + status: "{}" + - updated_at: updated_at + payload: "{}" + max_attempts: 6 + created_at: created_at + id: id + last_error: last_error + run_at: run_at + type: type + queue: queue + attempts: 0 + status: "{}" + page_size: 5 + properties: + items: + items: + $ref: "#/components/schemas/dto.Job" + type: array + page: + description: "example: 1" + type: integer + page_size: + description: "example: 25" + type: integer + total: + description: "example: 120" + type: integer + type: object + dto.QueueInfo: + example: + running: 1 + scheduled: 5 + pending: 6 + name: name + failed: 0 + properties: + failed: + description: "example: 5" + type: integer + name: + description: "example: default" + type: string + pending: + description: "example: 42" + type: integer + running: + description: "example: 3" + type: integer + scheduled: + description: "example: 7" + type: integer + type: object dto.RefreshRequest: properties: refresh_token: @@ -2182,6 +2750,13 @@ components: example: Bearer type: string type: object + dto.UpdateAnnotationRequest: + properties: + key: + type: string + value: + type: string + type: object dto.UpdateLabelRequest: properties: key: @@ -2243,6 +2818,7 @@ components: id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91 is_verified: true user: + is_admin: true avatar_url: avatar_url updated_at: 2000-01-23T04:56:07.000+00:00 is_disabled: true @@ -2258,6 +2834,7 @@ components: id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91 is_verified: true user: + is_admin: true avatar_url: avatar_url updated_at: 2000-01-23T04:56:07.000+00:00 is_disabled: true @@ -2266,6 +2843,7 @@ components: id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91 display_name: display_name email: email + is_admin: true avatar_url: avatar_url updated_at: 2000-01-23T04:56:07.000+00:00 is_disabled: true @@ -2300,6 +2878,8 @@ components: description: "example: 3fa85f64-5717-4562-b3fc-2c963f66afa6" format: uuid type: string + is_admin: + type: boolean is_disabled: type: boolean organizations: @@ -2491,6 +3071,7 @@ components: type: object models.User: example: + is_admin: true avatar_url: avatar_url updated_at: 2000-01-23T04:56:07.000+00:00 is_disabled: true @@ -2510,6 +3091,8 @@ components: description: "example: 3fa85f64-5717-4562-b3fc-2c963f66afa6" format: uuid type: string + is_admin: + type: boolean is_disabled: type: boolean primary_email: @@ -2527,6 +3110,7 @@ components: id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91 is_verified: true user: + is_admin: true avatar_url: avatar_url updated_at: 2000-01-23T04:56:07.000+00:00 is_disabled: true diff --git a/sdk/go/api_annotations.go b/sdk/go/api_annotations.go index 68d4c65..2199989 100644 --- a/sdk/go/api_annotations.go +++ b/sdk/go/api_annotations.go @@ -22,12 +22,417 @@ import ( // AnnotationsAPIService AnnotationsAPI service type AnnotationsAPIService service +type ApiCreateAnnotationRequest struct { + ctx context.Context + ApiService *AnnotationsAPIService + body *DtoCreateAnnotationRequest + xOrgID *string +} + +// Annotation payload +func (r ApiCreateAnnotationRequest) Body(body DtoCreateAnnotationRequest) ApiCreateAnnotationRequest { + r.body = &body + return r +} + +// Organization UUID +func (r ApiCreateAnnotationRequest) XOrgID(xOrgID string) ApiCreateAnnotationRequest { + r.xOrgID = &xOrgID + return r +} + +func (r ApiCreateAnnotationRequest) Execute() (*DtoAnnotationResponse, *http.Response, error) { + return r.ApiService.CreateAnnotationExecute(r) +} + +/* +CreateAnnotation Create annotation (org scoped) + +Creates an annotation. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiCreateAnnotationRequest +*/ +func (a *AnnotationsAPIService) CreateAnnotation(ctx context.Context) ApiCreateAnnotationRequest { + return ApiCreateAnnotationRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return DtoAnnotationResponse +func (a *AnnotationsAPIService) CreateAnnotationExecute(r ApiCreateAnnotationRequest) (*DtoAnnotationResponse, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *DtoAnnotationResponse + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "AnnotationsAPIService.CreateAnnotation") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/annotations" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.body == nil { + return localVarReturnValue, nil, reportError("body is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.xOrgID != nil { + parameterAddToHeaderOrQuery(localVarHeaderParams, "X-Org-ID", r.xOrgID, "", "") + } + // body params + localVarPostBody = r.body + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["OrgKeyAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["X-ORG-KEY"] = key + } + } + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["OrgSecretAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["X-ORG-SECRET"] = key + } + } + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["BearerAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 401 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 500 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiDeleteAnnotationRequest struct { + ctx context.Context + ApiService *AnnotationsAPIService + id string + xOrgID *string +} + +// Organization UUID +func (r ApiDeleteAnnotationRequest) XOrgID(xOrgID string) ApiDeleteAnnotationRequest { + r.xOrgID = &xOrgID + return r +} + +func (r ApiDeleteAnnotationRequest) Execute() (string, *http.Response, error) { + return r.ApiService.DeleteAnnotationExecute(r) +} + +/* +DeleteAnnotation Delete annotation (org scoped) + +Permanently deletes the annotation. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param id Annotation ID (UUID) + @return ApiDeleteAnnotationRequest +*/ +func (a *AnnotationsAPIService) DeleteAnnotation(ctx context.Context, id string) ApiDeleteAnnotationRequest { + return ApiDeleteAnnotationRequest{ + ApiService: a, + ctx: ctx, + id: id, + } +} + +// Execute executes the request +// +// @return string +func (a *AnnotationsAPIService) DeleteAnnotationExecute(r ApiDeleteAnnotationRequest) (string, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodDelete + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue string + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "AnnotationsAPIService.DeleteAnnotation") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/annotations/{id}" + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.xOrgID != nil { + parameterAddToHeaderOrQuery(localVarHeaderParams, "X-Org-ID", r.xOrgID, "", "") + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["OrgKeyAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["X-ORG-KEY"] = key + } + } + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["OrgSecretAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["X-ORG-SECRET"] = key + } + } + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["BearerAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 401 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 500 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + type ApiGetAnnotationRequest struct { ctx context.Context ApiService *AnnotationsAPIService id string xOrgID *string - include *string } // Organization UUID @@ -36,12 +441,6 @@ func (r ApiGetAnnotationRequest) XOrgID(xOrgID string) ApiGetAnnotationRequest { return r } -// Optional: node_pools -func (r ApiGetAnnotationRequest) Include(include string) ApiGetAnnotationRequest { - r.include = &include - return r -} - func (r ApiGetAnnotationRequest) Execute() (*DtoAnnotationResponse, *http.Response, error) { return r.ApiService.GetAnnotationExecute(r) } @@ -86,9 +485,6 @@ func (a *AnnotationsAPIService) GetAnnotationExecute(r ApiGetAnnotationRequest) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.include != nil { - parameterAddToHeaderOrQuery(localVarQueryParams, "include", r.include, "", "") - } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -455,3 +851,225 @@ func (a *AnnotationsAPIService) ListAnnotationsExecute(r ApiListAnnotationsReque return localVarReturnValue, localVarHTTPResponse, nil } + +type ApiUpdateAnnotationRequest struct { + ctx context.Context + ApiService *AnnotationsAPIService + id string + body *DtoUpdateAnnotationRequest + xOrgID *string +} + +// Fields to update +func (r ApiUpdateAnnotationRequest) Body(body DtoUpdateAnnotationRequest) ApiUpdateAnnotationRequest { + r.body = &body + return r +} + +// Organization UUID +func (r ApiUpdateAnnotationRequest) XOrgID(xOrgID string) ApiUpdateAnnotationRequest { + r.xOrgID = &xOrgID + return r +} + +func (r ApiUpdateAnnotationRequest) Execute() (*DtoAnnotationResponse, *http.Response, error) { + return r.ApiService.UpdateAnnotationExecute(r) +} + +/* +UpdateAnnotation Update annotation (org scoped) + +Partially update annotation fields. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param id Annotation ID (UUID) + @return ApiUpdateAnnotationRequest +*/ +func (a *AnnotationsAPIService) UpdateAnnotation(ctx context.Context, id string) ApiUpdateAnnotationRequest { + return ApiUpdateAnnotationRequest{ + ApiService: a, + ctx: ctx, + id: id, + } +} + +// Execute executes the request +// +// @return DtoAnnotationResponse +func (a *AnnotationsAPIService) UpdateAnnotationExecute(r ApiUpdateAnnotationRequest) (*DtoAnnotationResponse, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPatch + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *DtoAnnotationResponse + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "AnnotationsAPIService.UpdateAnnotation") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/annotations/{id}" + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.body == nil { + return localVarReturnValue, nil, reportError("body is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.xOrgID != nil { + parameterAddToHeaderOrQuery(localVarHeaderParams, "X-Org-ID", r.xOrgID, "", "") + } + // body params + localVarPostBody = r.body + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["OrgKeyAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["X-ORG-KEY"] = key + } + } + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["OrgSecretAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["X-ORG-SECRET"] = key + } + } + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["BearerAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 401 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 404 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 500 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} diff --git a/sdk/go/api_archer_admin.go b/sdk/go/api_archer_admin.go new file mode 100644 index 0000000..1ab3adb --- /dev/null +++ b/sdk/go/api_archer_admin.go @@ -0,0 +1,864 @@ +/* +AutoGlue API + +API for managing K3s clusters across cloud providers + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package autoglue + +import ( + "bytes" + "context" + "io" + "net/http" + "net/url" + "strings" +) + +// ArcherAdminAPIService ArcherAdminAPI service +type ArcherAdminAPIService service + +type ApiAdminCancelArcherJobRequest struct { + ctx context.Context + ApiService *ArcherAdminAPIService + id string +} + +func (r ApiAdminCancelArcherJobRequest) Execute() (*DtoJob, *http.Response, error) { + return r.ApiService.AdminCancelArcherJobExecute(r) +} + +/* +AdminCancelArcherJob Cancel an Archer job (admin) + +Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param id Job ID + @return ApiAdminCancelArcherJobRequest +*/ +func (a *ArcherAdminAPIService) AdminCancelArcherJob(ctx context.Context, id string) ApiAdminCancelArcherJobRequest { + return ApiAdminCancelArcherJobRequest{ + ApiService: a, + ctx: ctx, + id: id, + } +} + +// Execute executes the request +// +// @return DtoJob +func (a *ArcherAdminAPIService) AdminCancelArcherJobExecute(r ApiAdminCancelArcherJobRequest) (*DtoJob, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *DtoJob + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ArcherAdminAPIService.AdminCancelArcherJob") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/admin/archer/jobs/{id}/cancel" + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["BearerAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 401 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 404 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiAdminEnqueueArcherJobRequest struct { + ctx context.Context + ApiService *ArcherAdminAPIService + body *map[string]interface{} +} + +// Job parameters +func (r ApiAdminEnqueueArcherJobRequest) Body(body map[string]interface{}) ApiAdminEnqueueArcherJobRequest { + r.body = &body + return r +} + +func (r ApiAdminEnqueueArcherJobRequest) Execute() (*DtoJob, *http.Response, error) { + return r.ApiService.AdminEnqueueArcherJobExecute(r) +} + +/* +AdminEnqueueArcherJob Enqueue a new Archer job (admin) + +Create a job immediately or schedule it for the future via `run_at`. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiAdminEnqueueArcherJobRequest +*/ +func (a *ArcherAdminAPIService) AdminEnqueueArcherJob(ctx context.Context) ApiAdminEnqueueArcherJobRequest { + return ApiAdminEnqueueArcherJobRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return DtoJob +func (a *ArcherAdminAPIService) AdminEnqueueArcherJobExecute(r ApiAdminEnqueueArcherJobRequest) (*DtoJob, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *DtoJob + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ArcherAdminAPIService.AdminEnqueueArcherJob") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/admin/archer/jobs" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.body == nil { + return localVarReturnValue, nil, reportError("body is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.body + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["BearerAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 401 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 500 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiAdminListArcherJobsRequest struct { + ctx context.Context + ApiService *ArcherAdminAPIService + status *string + queue *string + q *string + page *int32 + pageSize *int32 +} + +// Filter by status +func (r ApiAdminListArcherJobsRequest) Status(status string) ApiAdminListArcherJobsRequest { + r.status = &status + return r +} + +// Filter by queue name / worker name +func (r ApiAdminListArcherJobsRequest) Queue(queue string) ApiAdminListArcherJobsRequest { + r.queue = &queue + return r +} + +// Free-text search +func (r ApiAdminListArcherJobsRequest) Q(q string) ApiAdminListArcherJobsRequest { + r.q = &q + return r +} + +// Page number +func (r ApiAdminListArcherJobsRequest) Page(page int32) ApiAdminListArcherJobsRequest { + r.page = &page + return r +} + +// Items per page +func (r ApiAdminListArcherJobsRequest) PageSize(pageSize int32) ApiAdminListArcherJobsRequest { + r.pageSize = &pageSize + return r +} + +func (r ApiAdminListArcherJobsRequest) Execute() (*DtoPageJob, *http.Response, error) { + return r.ApiService.AdminListArcherJobsExecute(r) +} + +/* +AdminListArcherJobs List Archer jobs (admin) + +Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent). + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiAdminListArcherJobsRequest +*/ +func (a *ArcherAdminAPIService) AdminListArcherJobs(ctx context.Context) ApiAdminListArcherJobsRequest { + return ApiAdminListArcherJobsRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return DtoPageJob +func (a *ArcherAdminAPIService) AdminListArcherJobsExecute(r ApiAdminListArcherJobsRequest) (*DtoPageJob, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *DtoPageJob + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ArcherAdminAPIService.AdminListArcherJobs") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/admin/archer/jobs" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if r.status != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "status", r.status, "", "") + } + if r.queue != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "queue", r.queue, "", "") + } + if r.q != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "q", r.q, "", "") + } + if r.page != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "page", r.page, "", "") + } else { + var defaultValue int32 = 1 + parameterAddToHeaderOrQuery(localVarQueryParams, "page", defaultValue, "", "") + r.page = &defaultValue + } + if r.pageSize != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "page_size", r.pageSize, "", "") + } else { + var defaultValue int32 = 25 + parameterAddToHeaderOrQuery(localVarQueryParams, "page_size", defaultValue, "", "") + r.pageSize = &defaultValue + } + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["BearerAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 401 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 500 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiAdminListArcherQueuesRequest struct { + ctx context.Context + ApiService *ArcherAdminAPIService +} + +func (r ApiAdminListArcherQueuesRequest) Execute() ([]DtoQueueInfo, *http.Response, error) { + return r.ApiService.AdminListArcherQueuesExecute(r) +} + +/* +AdminListArcherQueues List Archer queues (admin) + +Summary metrics per queue (pending, running, failed, scheduled). + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiAdminListArcherQueuesRequest +*/ +func (a *ArcherAdminAPIService) AdminListArcherQueues(ctx context.Context) ApiAdminListArcherQueuesRequest { + return ApiAdminListArcherQueuesRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return []DtoQueueInfo +func (a *ArcherAdminAPIService) AdminListArcherQueuesExecute(r ApiAdminListArcherQueuesRequest) ([]DtoQueueInfo, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []DtoQueueInfo + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ArcherAdminAPIService.AdminListArcherQueues") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/admin/archer/queues" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["BearerAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 401 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 500 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiAdminRetryArcherJobRequest struct { + ctx context.Context + ApiService *ArcherAdminAPIService + id string +} + +func (r ApiAdminRetryArcherJobRequest) Execute() (*DtoJob, *http.Response, error) { + return r.ApiService.AdminRetryArcherJobExecute(r) +} + +/* +AdminRetryArcherJob Retry a failed/canceled Archer job (admin) + +Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param id Job ID + @return ApiAdminRetryArcherJobRequest +*/ +func (a *ArcherAdminAPIService) AdminRetryArcherJob(ctx context.Context, id string) ApiAdminRetryArcherJobRequest { + return ApiAdminRetryArcherJobRequest{ + ApiService: a, + ctx: ctx, + id: id, + } +} + +// Execute executes the request +// +// @return DtoJob +func (a *ArcherAdminAPIService) AdminRetryArcherJobExecute(r ApiAdminRetryArcherJobRequest) (*DtoJob, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *DtoJob + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ArcherAdminAPIService.AdminRetryArcherJob") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/admin/archer/jobs/{id}/retry" + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["BearerAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 401 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 404 { + var v string + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} diff --git a/sdk/go/client.go b/sdk/go/client.go index bcd7204..e9ed526 100644 --- a/sdk/go/client.go +++ b/sdk/go/client.go @@ -50,6 +50,8 @@ type APIClient struct { AnnotationsAPI *AnnotationsAPIService + ArcherAdminAPI *ArcherAdminAPIService + AuthAPI *AuthAPIService HealthAPI *HealthAPIService @@ -86,6 +88,7 @@ func NewAPIClient(cfg *Configuration) *APIClient { // API Services c.AnnotationsAPI = (*AnnotationsAPIService)(&c.common) + c.ArcherAdminAPI = (*ArcherAdminAPIService)(&c.common) c.AuthAPI = (*AuthAPIService)(&c.common) c.HealthAPI = (*HealthAPIService)(&c.common) c.LabelsAPI = (*LabelsAPIService)(&c.common) diff --git a/sdk/go/docs/AnnotationsAPI.md b/sdk/go/docs/AnnotationsAPI.md index 1a7735e..1642aad 100644 --- a/sdk/go/docs/AnnotationsAPI.md +++ b/sdk/go/docs/AnnotationsAPI.md @@ -4,14 +4,157 @@ All URIs are relative to *http://localhost:8080/api/v1* Method | HTTP request | Description ------------- | ------------- | ------------- +[**CreateAnnotation**](AnnotationsAPI.md#CreateAnnotation) | **Post** /annotations | Create annotation (org scoped) +[**DeleteAnnotation**](AnnotationsAPI.md#DeleteAnnotation) | **Delete** /annotations/{id} | Delete annotation (org scoped) [**GetAnnotation**](AnnotationsAPI.md#GetAnnotation) | **Get** /annotations/{id} | Get annotation by ID (org scoped) [**ListAnnotations**](AnnotationsAPI.md#ListAnnotations) | **Get** /annotations | List annotations (org scoped) +[**UpdateAnnotation**](AnnotationsAPI.md#UpdateAnnotation) | **Patch** /annotations/{id} | Update annotation (org scoped) +## CreateAnnotation + +> DtoAnnotationResponse CreateAnnotation(ctx).Body(body).XOrgID(xOrgID).Execute() + +Create annotation (org scoped) + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/glueops/autoglue-sdk-go" +) + +func main() { + body := *openapiclient.NewDtoCreateAnnotationRequest() // DtoCreateAnnotationRequest | Annotation payload + xOrgID := "xOrgID_example" // string | Organization UUID (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.AnnotationsAPI.CreateAnnotation(context.Background()).Body(body).XOrgID(xOrgID).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `AnnotationsAPI.CreateAnnotation``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `CreateAnnotation`: DtoAnnotationResponse + fmt.Fprintf(os.Stdout, "Response from `AnnotationsAPI.CreateAnnotation`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiCreateAnnotationRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**DtoCreateAnnotationRequest**](DtoCreateAnnotationRequest.md) | Annotation payload | + **xOrgID** | **string** | Organization UUID | + +### Return type + +[**DtoAnnotationResponse**](DtoAnnotationResponse.md) + +### Authorization + +[OrgKeyAuth](../README.md#OrgKeyAuth), [OrgSecretAuth](../README.md#OrgSecretAuth), [BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## DeleteAnnotation + +> string DeleteAnnotation(ctx, id).XOrgID(xOrgID).Execute() + +Delete annotation (org scoped) + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/glueops/autoglue-sdk-go" +) + +func main() { + id := "id_example" // string | Annotation ID (UUID) + xOrgID := "xOrgID_example" // string | Organization UUID (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.AnnotationsAPI.DeleteAnnotation(context.Background(), id).XOrgID(xOrgID).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `AnnotationsAPI.DeleteAnnotation``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `DeleteAnnotation`: string + fmt.Fprintf(os.Stdout, "Response from `AnnotationsAPI.DeleteAnnotation`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**id** | **string** | Annotation ID (UUID) | + +### Other Parameters + +Other parameters are passed through a pointer to a apiDeleteAnnotationRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + **xOrgID** | **string** | Organization UUID | + +### Return type + +**string** + +### Authorization + +[OrgKeyAuth](../README.md#OrgKeyAuth), [OrgSecretAuth](../README.md#OrgSecretAuth), [BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## GetAnnotation -> DtoAnnotationResponse GetAnnotation(ctx, id).XOrgID(xOrgID).Include(include).Execute() +> DtoAnnotationResponse GetAnnotation(ctx, id).XOrgID(xOrgID).Execute() Get annotation by ID (org scoped) @@ -32,11 +175,10 @@ import ( func main() { id := "id_example" // string | Annotation ID (UUID) xOrgID := "xOrgID_example" // string | Organization UUID (optional) - include := "include_example" // string | Optional: node_pools (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.AnnotationsAPI.GetAnnotation(context.Background(), id).XOrgID(xOrgID).Include(include).Execute() + resp, r, err := apiClient.AnnotationsAPI.GetAnnotation(context.Background(), id).XOrgID(xOrgID).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `AnnotationsAPI.GetAnnotation``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -63,7 +205,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **xOrgID** | **string** | Organization UUID | - **include** | **string** | Optional: node_pools | ### Return type @@ -154,3 +295,77 @@ Name | Type | Description | Notes [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +## UpdateAnnotation + +> DtoAnnotationResponse UpdateAnnotation(ctx, id).Body(body).XOrgID(xOrgID).Execute() + +Update annotation (org scoped) + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/glueops/autoglue-sdk-go" +) + +func main() { + id := "id_example" // string | Annotation ID (UUID) + body := *openapiclient.NewDtoUpdateAnnotationRequest() // DtoUpdateAnnotationRequest | Fields to update + xOrgID := "xOrgID_example" // string | Organization UUID (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.AnnotationsAPI.UpdateAnnotation(context.Background(), id).Body(body).XOrgID(xOrgID).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `AnnotationsAPI.UpdateAnnotation``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `UpdateAnnotation`: DtoAnnotationResponse + fmt.Fprintf(os.Stdout, "Response from `AnnotationsAPI.UpdateAnnotation`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**id** | **string** | Annotation ID (UUID) | + +### Other Parameters + +Other parameters are passed through a pointer to a apiUpdateAnnotationRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + **body** | [**DtoUpdateAnnotationRequest**](DtoUpdateAnnotationRequest.md) | Fields to update | + **xOrgID** | **string** | Organization UUID | + +### Return type + +[**DtoAnnotationResponse**](DtoAnnotationResponse.md) + +### Authorization + +[OrgKeyAuth](../README.md#OrgKeyAuth), [OrgSecretAuth](../README.md#OrgSecretAuth), [BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + diff --git a/sdk/go/docs/ArcherAdminAPI.md b/sdk/go/docs/ArcherAdminAPI.md new file mode 100644 index 0000000..cfdaf15 --- /dev/null +++ b/sdk/go/docs/ArcherAdminAPI.md @@ -0,0 +1,354 @@ +# \ArcherAdminAPI + +All URIs are relative to *http://localhost:8080/api/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**AdminCancelArcherJob**](ArcherAdminAPI.md#AdminCancelArcherJob) | **Post** /admin/archer/jobs/{id}/cancel | Cancel an Archer job (admin) +[**AdminEnqueueArcherJob**](ArcherAdminAPI.md#AdminEnqueueArcherJob) | **Post** /admin/archer/jobs | Enqueue a new Archer job (admin) +[**AdminListArcherJobs**](ArcherAdminAPI.md#AdminListArcherJobs) | **Get** /admin/archer/jobs | List Archer jobs (admin) +[**AdminListArcherQueues**](ArcherAdminAPI.md#AdminListArcherQueues) | **Get** /admin/archer/queues | List Archer queues (admin) +[**AdminRetryArcherJob**](ArcherAdminAPI.md#AdminRetryArcherJob) | **Post** /admin/archer/jobs/{id}/retry | Retry a failed/canceled Archer job (admin) + + + +## AdminCancelArcherJob + +> DtoJob AdminCancelArcherJob(ctx, id).Execute() + +Cancel an Archer job (admin) + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/glueops/autoglue-sdk-go" +) + +func main() { + id := "id_example" // string | Job ID + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.ArcherAdminAPI.AdminCancelArcherJob(context.Background(), id).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `ArcherAdminAPI.AdminCancelArcherJob``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `AdminCancelArcherJob`: DtoJob + fmt.Fprintf(os.Stdout, "Response from `ArcherAdminAPI.AdminCancelArcherJob`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**id** | **string** | Job ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiAdminCancelArcherJobRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + +[**DtoJob**](DtoJob.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## AdminEnqueueArcherJob + +> DtoJob AdminEnqueueArcherJob(ctx).Body(body).Execute() + +Enqueue a new Archer job (admin) + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/glueops/autoglue-sdk-go" +) + +func main() { + body := map[string]interface{}{ ... } // map[string]interface{} | Job parameters + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.ArcherAdminAPI.AdminEnqueueArcherJob(context.Background()).Body(body).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `ArcherAdminAPI.AdminEnqueueArcherJob``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `AdminEnqueueArcherJob`: DtoJob + fmt.Fprintf(os.Stdout, "Response from `ArcherAdminAPI.AdminEnqueueArcherJob`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiAdminEnqueueArcherJobRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | **map[string]interface{}** | Job parameters | + +### Return type + +[**DtoJob**](DtoJob.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## AdminListArcherJobs + +> DtoPageJob AdminListArcherJobs(ctx).Status(status).Queue(queue).Q(q).Page(page).PageSize(pageSize).Execute() + +List Archer jobs (admin) + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/glueops/autoglue-sdk-go" +) + +func main() { + status := "status_example" // string | Filter by status (optional) + queue := "queue_example" // string | Filter by queue name / worker name (optional) + q := "q_example" // string | Free-text search (optional) + page := int32(56) // int32 | Page number (optional) (default to 1) + pageSize := int32(56) // int32 | Items per page (optional) (default to 25) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.ArcherAdminAPI.AdminListArcherJobs(context.Background()).Status(status).Queue(queue).Q(q).Page(page).PageSize(pageSize).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `ArcherAdminAPI.AdminListArcherJobs``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `AdminListArcherJobs`: DtoPageJob + fmt.Fprintf(os.Stdout, "Response from `ArcherAdminAPI.AdminListArcherJobs`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiAdminListArcherJobsRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **status** | **string** | Filter by status | + **queue** | **string** | Filter by queue name / worker name | + **q** | **string** | Free-text search | + **page** | **int32** | Page number | [default to 1] + **pageSize** | **int32** | Items per page | [default to 25] + +### Return type + +[**DtoPageJob**](DtoPageJob.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## AdminListArcherQueues + +> []DtoQueueInfo AdminListArcherQueues(ctx).Execute() + +List Archer queues (admin) + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/glueops/autoglue-sdk-go" +) + +func main() { + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.ArcherAdminAPI.AdminListArcherQueues(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `ArcherAdminAPI.AdminListArcherQueues``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `AdminListArcherQueues`: []DtoQueueInfo + fmt.Fprintf(os.Stdout, "Response from `ArcherAdminAPI.AdminListArcherQueues`: %v\n", resp) +} +``` + +### Path Parameters + +This endpoint does not need any parameter. + +### Other Parameters + +Other parameters are passed through a pointer to a apiAdminListArcherQueuesRequest struct via the builder pattern + + +### Return type + +[**[]DtoQueueInfo**](DtoQueueInfo.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## AdminRetryArcherJob + +> DtoJob AdminRetryArcherJob(ctx, id).Execute() + +Retry a failed/canceled Archer job (admin) + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/glueops/autoglue-sdk-go" +) + +func main() { + id := "id_example" // string | Job ID + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.ArcherAdminAPI.AdminRetryArcherJob(context.Background(), id).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `ArcherAdminAPI.AdminRetryArcherJob``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `AdminRetryArcherJob`: DtoJob + fmt.Fprintf(os.Stdout, "Response from `ArcherAdminAPI.AdminRetryArcherJob`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**id** | **string** | Job ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiAdminRetryArcherJobRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + +[**DtoJob**](DtoJob.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + diff --git a/sdk/go/docs/DtoCreateAnnotationRequest.md b/sdk/go/docs/DtoCreateAnnotationRequest.md new file mode 100644 index 0000000..80f472f --- /dev/null +++ b/sdk/go/docs/DtoCreateAnnotationRequest.md @@ -0,0 +1,82 @@ +# DtoCreateAnnotationRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Key** | Pointer to **string** | | [optional] +**Value** | Pointer to **string** | | [optional] + +## Methods + +### NewDtoCreateAnnotationRequest + +`func NewDtoCreateAnnotationRequest() *DtoCreateAnnotationRequest` + +NewDtoCreateAnnotationRequest instantiates a new DtoCreateAnnotationRequest object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewDtoCreateAnnotationRequestWithDefaults + +`func NewDtoCreateAnnotationRequestWithDefaults() *DtoCreateAnnotationRequest` + +NewDtoCreateAnnotationRequestWithDefaults instantiates a new DtoCreateAnnotationRequest object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetKey + +`func (o *DtoCreateAnnotationRequest) GetKey() string` + +GetKey returns the Key field if non-nil, zero value otherwise. + +### GetKeyOk + +`func (o *DtoCreateAnnotationRequest) GetKeyOk() (*string, bool)` + +GetKeyOk returns a tuple with the Key field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetKey + +`func (o *DtoCreateAnnotationRequest) SetKey(v string)` + +SetKey sets Key field to given value. + +### HasKey + +`func (o *DtoCreateAnnotationRequest) HasKey() bool` + +HasKey returns a boolean if a field has been set. + +### GetValue + +`func (o *DtoCreateAnnotationRequest) GetValue() string` + +GetValue returns the Value field if non-nil, zero value otherwise. + +### GetValueOk + +`func (o *DtoCreateAnnotationRequest) GetValueOk() (*string, bool)` + +GetValueOk returns a tuple with the Value field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetValue + +`func (o *DtoCreateAnnotationRequest) SetValue(v string)` + +SetValue sets Value field to given value. + +### HasValue + +`func (o *DtoCreateAnnotationRequest) HasValue() bool` + +HasValue returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/sdk/go/docs/DtoJob.md b/sdk/go/docs/DtoJob.md new file mode 100644 index 0000000..bb4ff37 --- /dev/null +++ b/sdk/go/docs/DtoJob.md @@ -0,0 +1,316 @@ +# DtoJob + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Attempts** | Pointer to **int32** | example: 0 | [optional] +**CreatedAt** | Pointer to **string** | example: 2025-11-04T09:30:00Z | [optional] +**Id** | Pointer to **string** | example: 01HF7SZK8Z8WG1M3J7S2Z8M2N6 | [optional] +**LastError** | Pointer to **string** | example: dial tcp: i/o timeout | [optional] +**MaxAttempts** | Pointer to **int32** | example: 3 | [optional] +**Payload** | Pointer to **map[string]interface{}** | arbitrary JSON payload | [optional] +**Queue** | Pointer to **string** | example: default | [optional] +**RunAt** | Pointer to **string** | example: 2025-11-05T08:00:00Z | [optional] +**Status** | Pointer to [**DtoJobStatus**](DtoJobStatus.md) | enum: queued,running,succeeded,failed,canceled,retrying,scheduled example: queued | [optional] +**Type** | Pointer to **string** | example: email.send | [optional] +**UpdatedAt** | Pointer to **string** | example: 2025-11-04T09:31:00Z | [optional] + +## Methods + +### NewDtoJob + +`func NewDtoJob() *DtoJob` + +NewDtoJob instantiates a new DtoJob object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewDtoJobWithDefaults + +`func NewDtoJobWithDefaults() *DtoJob` + +NewDtoJobWithDefaults instantiates a new DtoJob object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetAttempts + +`func (o *DtoJob) GetAttempts() int32` + +GetAttempts returns the Attempts field if non-nil, zero value otherwise. + +### GetAttemptsOk + +`func (o *DtoJob) GetAttemptsOk() (*int32, bool)` + +GetAttemptsOk returns a tuple with the Attempts field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAttempts + +`func (o *DtoJob) SetAttempts(v int32)` + +SetAttempts sets Attempts field to given value. + +### HasAttempts + +`func (o *DtoJob) HasAttempts() bool` + +HasAttempts returns a boolean if a field has been set. + +### GetCreatedAt + +`func (o *DtoJob) GetCreatedAt() string` + +GetCreatedAt returns the CreatedAt field if non-nil, zero value otherwise. + +### GetCreatedAtOk + +`func (o *DtoJob) GetCreatedAtOk() (*string, bool)` + +GetCreatedAtOk returns a tuple with the CreatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCreatedAt + +`func (o *DtoJob) SetCreatedAt(v string)` + +SetCreatedAt sets CreatedAt field to given value. + +### HasCreatedAt + +`func (o *DtoJob) HasCreatedAt() bool` + +HasCreatedAt returns a boolean if a field has been set. + +### GetId + +`func (o *DtoJob) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *DtoJob) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *DtoJob) SetId(v string)` + +SetId sets Id field to given value. + +### HasId + +`func (o *DtoJob) HasId() bool` + +HasId returns a boolean if a field has been set. + +### GetLastError + +`func (o *DtoJob) GetLastError() string` + +GetLastError returns the LastError field if non-nil, zero value otherwise. + +### GetLastErrorOk + +`func (o *DtoJob) GetLastErrorOk() (*string, bool)` + +GetLastErrorOk returns a tuple with the LastError field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastError + +`func (o *DtoJob) SetLastError(v string)` + +SetLastError sets LastError field to given value. + +### HasLastError + +`func (o *DtoJob) HasLastError() bool` + +HasLastError returns a boolean if a field has been set. + +### GetMaxAttempts + +`func (o *DtoJob) GetMaxAttempts() int32` + +GetMaxAttempts returns the MaxAttempts field if non-nil, zero value otherwise. + +### GetMaxAttemptsOk + +`func (o *DtoJob) GetMaxAttemptsOk() (*int32, bool)` + +GetMaxAttemptsOk returns a tuple with the MaxAttempts field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMaxAttempts + +`func (o *DtoJob) SetMaxAttempts(v int32)` + +SetMaxAttempts sets MaxAttempts field to given value. + +### HasMaxAttempts + +`func (o *DtoJob) HasMaxAttempts() bool` + +HasMaxAttempts returns a boolean if a field has been set. + +### GetPayload + +`func (o *DtoJob) GetPayload() map[string]interface{}` + +GetPayload returns the Payload field if non-nil, zero value otherwise. + +### GetPayloadOk + +`func (o *DtoJob) GetPayloadOk() (*map[string]interface{}, bool)` + +GetPayloadOk returns a tuple with the Payload field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPayload + +`func (o *DtoJob) SetPayload(v map[string]interface{})` + +SetPayload sets Payload field to given value. + +### HasPayload + +`func (o *DtoJob) HasPayload() bool` + +HasPayload returns a boolean if a field has been set. + +### GetQueue + +`func (o *DtoJob) GetQueue() string` + +GetQueue returns the Queue field if non-nil, zero value otherwise. + +### GetQueueOk + +`func (o *DtoJob) GetQueueOk() (*string, bool)` + +GetQueueOk returns a tuple with the Queue field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetQueue + +`func (o *DtoJob) SetQueue(v string)` + +SetQueue sets Queue field to given value. + +### HasQueue + +`func (o *DtoJob) HasQueue() bool` + +HasQueue returns a boolean if a field has been set. + +### GetRunAt + +`func (o *DtoJob) GetRunAt() string` + +GetRunAt returns the RunAt field if non-nil, zero value otherwise. + +### GetRunAtOk + +`func (o *DtoJob) GetRunAtOk() (*string, bool)` + +GetRunAtOk returns a tuple with the RunAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRunAt + +`func (o *DtoJob) SetRunAt(v string)` + +SetRunAt sets RunAt field to given value. + +### HasRunAt + +`func (o *DtoJob) HasRunAt() bool` + +HasRunAt returns a boolean if a field has been set. + +### GetStatus + +`func (o *DtoJob) GetStatus() DtoJobStatus` + +GetStatus returns the Status field if non-nil, zero value otherwise. + +### GetStatusOk + +`func (o *DtoJob) GetStatusOk() (*DtoJobStatus, bool)` + +GetStatusOk returns a tuple with the Status field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetStatus + +`func (o *DtoJob) SetStatus(v DtoJobStatus)` + +SetStatus sets Status field to given value. + +### HasStatus + +`func (o *DtoJob) HasStatus() bool` + +HasStatus returns a boolean if a field has been set. + +### GetType + +`func (o *DtoJob) GetType() string` + +GetType returns the Type field if non-nil, zero value otherwise. + +### GetTypeOk + +`func (o *DtoJob) GetTypeOk() (*string, bool)` + +GetTypeOk returns a tuple with the Type field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetType + +`func (o *DtoJob) SetType(v string)` + +SetType sets Type field to given value. + +### HasType + +`func (o *DtoJob) HasType() bool` + +HasType returns a boolean if a field has been set. + +### GetUpdatedAt + +`func (o *DtoJob) GetUpdatedAt() string` + +GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. + +### GetUpdatedAtOk + +`func (o *DtoJob) GetUpdatedAtOk() (*string, bool)` + +GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdatedAt + +`func (o *DtoJob) SetUpdatedAt(v string)` + +SetUpdatedAt sets UpdatedAt field to given value. + +### HasUpdatedAt + +`func (o *DtoJob) HasUpdatedAt() bool` + +HasUpdatedAt returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/sdk/go/docs/DtoJobStatus.md b/sdk/go/docs/DtoJobStatus.md new file mode 100644 index 0000000..99d84df --- /dev/null +++ b/sdk/go/docs/DtoJobStatus.md @@ -0,0 +1,23 @@ +# DtoJobStatus + +## Enum + + +* `StatusQueued` (value: `"queued"`) + +* `StatusRunning` (value: `"running"`) + +* `StatusSucceeded` (value: `"succeeded"`) + +* `StatusFailed` (value: `"failed"`) + +* `StatusCanceled` (value: `"canceled"`) + +* `StatusRetrying` (value: `"retrying"`) + +* `StatusScheduled` (value: `"scheduled"`) + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/sdk/go/docs/DtoPageJob.md b/sdk/go/docs/DtoPageJob.md new file mode 100644 index 0000000..fadb7f1 --- /dev/null +++ b/sdk/go/docs/DtoPageJob.md @@ -0,0 +1,134 @@ +# DtoPageJob + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Items** | Pointer to [**[]DtoJob**](DtoJob.md) | | [optional] +**Page** | Pointer to **int32** | example: 1 | [optional] +**PageSize** | Pointer to **int32** | example: 25 | [optional] +**Total** | Pointer to **int32** | example: 120 | [optional] + +## Methods + +### NewDtoPageJob + +`func NewDtoPageJob() *DtoPageJob` + +NewDtoPageJob instantiates a new DtoPageJob object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewDtoPageJobWithDefaults + +`func NewDtoPageJobWithDefaults() *DtoPageJob` + +NewDtoPageJobWithDefaults instantiates a new DtoPageJob object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetItems + +`func (o *DtoPageJob) GetItems() []DtoJob` + +GetItems returns the Items field if non-nil, zero value otherwise. + +### GetItemsOk + +`func (o *DtoPageJob) GetItemsOk() (*[]DtoJob, bool)` + +GetItemsOk returns a tuple with the Items field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetItems + +`func (o *DtoPageJob) SetItems(v []DtoJob)` + +SetItems sets Items field to given value. + +### HasItems + +`func (o *DtoPageJob) HasItems() bool` + +HasItems returns a boolean if a field has been set. + +### GetPage + +`func (o *DtoPageJob) GetPage() int32` + +GetPage returns the Page field if non-nil, zero value otherwise. + +### GetPageOk + +`func (o *DtoPageJob) GetPageOk() (*int32, bool)` + +GetPageOk returns a tuple with the Page field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPage + +`func (o *DtoPageJob) SetPage(v int32)` + +SetPage sets Page field to given value. + +### HasPage + +`func (o *DtoPageJob) HasPage() bool` + +HasPage returns a boolean if a field has been set. + +### GetPageSize + +`func (o *DtoPageJob) GetPageSize() int32` + +GetPageSize returns the PageSize field if non-nil, zero value otherwise. + +### GetPageSizeOk + +`func (o *DtoPageJob) GetPageSizeOk() (*int32, bool)` + +GetPageSizeOk returns a tuple with the PageSize field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPageSize + +`func (o *DtoPageJob) SetPageSize(v int32)` + +SetPageSize sets PageSize field to given value. + +### HasPageSize + +`func (o *DtoPageJob) HasPageSize() bool` + +HasPageSize returns a boolean if a field has been set. + +### GetTotal + +`func (o *DtoPageJob) GetTotal() int32` + +GetTotal returns the Total field if non-nil, zero value otherwise. + +### GetTotalOk + +`func (o *DtoPageJob) GetTotalOk() (*int32, bool)` + +GetTotalOk returns a tuple with the Total field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTotal + +`func (o *DtoPageJob) SetTotal(v int32)` + +SetTotal sets Total field to given value. + +### HasTotal + +`func (o *DtoPageJob) HasTotal() bool` + +HasTotal returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/sdk/go/docs/DtoQueueInfo.md b/sdk/go/docs/DtoQueueInfo.md new file mode 100644 index 0000000..2a438bf --- /dev/null +++ b/sdk/go/docs/DtoQueueInfo.md @@ -0,0 +1,160 @@ +# DtoQueueInfo + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Failed** | Pointer to **int32** | example: 5 | [optional] +**Name** | Pointer to **string** | example: default | [optional] +**Pending** | Pointer to **int32** | example: 42 | [optional] +**Running** | Pointer to **int32** | example: 3 | [optional] +**Scheduled** | Pointer to **int32** | example: 7 | [optional] + +## Methods + +### NewDtoQueueInfo + +`func NewDtoQueueInfo() *DtoQueueInfo` + +NewDtoQueueInfo instantiates a new DtoQueueInfo object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewDtoQueueInfoWithDefaults + +`func NewDtoQueueInfoWithDefaults() *DtoQueueInfo` + +NewDtoQueueInfoWithDefaults instantiates a new DtoQueueInfo object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetFailed + +`func (o *DtoQueueInfo) GetFailed() int32` + +GetFailed returns the Failed field if non-nil, zero value otherwise. + +### GetFailedOk + +`func (o *DtoQueueInfo) GetFailedOk() (*int32, bool)` + +GetFailedOk returns a tuple with the Failed field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFailed + +`func (o *DtoQueueInfo) SetFailed(v int32)` + +SetFailed sets Failed field to given value. + +### HasFailed + +`func (o *DtoQueueInfo) HasFailed() bool` + +HasFailed returns a boolean if a field has been set. + +### GetName + +`func (o *DtoQueueInfo) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *DtoQueueInfo) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *DtoQueueInfo) SetName(v string)` + +SetName sets Name field to given value. + +### HasName + +`func (o *DtoQueueInfo) HasName() bool` + +HasName returns a boolean if a field has been set. + +### GetPending + +`func (o *DtoQueueInfo) GetPending() int32` + +GetPending returns the Pending field if non-nil, zero value otherwise. + +### GetPendingOk + +`func (o *DtoQueueInfo) GetPendingOk() (*int32, bool)` + +GetPendingOk returns a tuple with the Pending field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPending + +`func (o *DtoQueueInfo) SetPending(v int32)` + +SetPending sets Pending field to given value. + +### HasPending + +`func (o *DtoQueueInfo) HasPending() bool` + +HasPending returns a boolean if a field has been set. + +### GetRunning + +`func (o *DtoQueueInfo) GetRunning() int32` + +GetRunning returns the Running field if non-nil, zero value otherwise. + +### GetRunningOk + +`func (o *DtoQueueInfo) GetRunningOk() (*int32, bool)` + +GetRunningOk returns a tuple with the Running field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRunning + +`func (o *DtoQueueInfo) SetRunning(v int32)` + +SetRunning sets Running field to given value. + +### HasRunning + +`func (o *DtoQueueInfo) HasRunning() bool` + +HasRunning returns a boolean if a field has been set. + +### GetScheduled + +`func (o *DtoQueueInfo) GetScheduled() int32` + +GetScheduled returns the Scheduled field if non-nil, zero value otherwise. + +### GetScheduledOk + +`func (o *DtoQueueInfo) GetScheduledOk() (*int32, bool)` + +GetScheduledOk returns a tuple with the Scheduled field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetScheduled + +`func (o *DtoQueueInfo) SetScheduled(v int32)` + +SetScheduled sets Scheduled field to given value. + +### HasScheduled + +`func (o *DtoQueueInfo) HasScheduled() bool` + +HasScheduled returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/sdk/go/docs/DtoUpdateAnnotationRequest.md b/sdk/go/docs/DtoUpdateAnnotationRequest.md new file mode 100644 index 0000000..9e0408b --- /dev/null +++ b/sdk/go/docs/DtoUpdateAnnotationRequest.md @@ -0,0 +1,82 @@ +# DtoUpdateAnnotationRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Key** | Pointer to **string** | | [optional] +**Value** | Pointer to **string** | | [optional] + +## Methods + +### NewDtoUpdateAnnotationRequest + +`func NewDtoUpdateAnnotationRequest() *DtoUpdateAnnotationRequest` + +NewDtoUpdateAnnotationRequest instantiates a new DtoUpdateAnnotationRequest object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewDtoUpdateAnnotationRequestWithDefaults + +`func NewDtoUpdateAnnotationRequestWithDefaults() *DtoUpdateAnnotationRequest` + +NewDtoUpdateAnnotationRequestWithDefaults instantiates a new DtoUpdateAnnotationRequest object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetKey + +`func (o *DtoUpdateAnnotationRequest) GetKey() string` + +GetKey returns the Key field if non-nil, zero value otherwise. + +### GetKeyOk + +`func (o *DtoUpdateAnnotationRequest) GetKeyOk() (*string, bool)` + +GetKeyOk returns a tuple with the Key field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetKey + +`func (o *DtoUpdateAnnotationRequest) SetKey(v string)` + +SetKey sets Key field to given value. + +### HasKey + +`func (o *DtoUpdateAnnotationRequest) HasKey() bool` + +HasKey returns a boolean if a field has been set. + +### GetValue + +`func (o *DtoUpdateAnnotationRequest) GetValue() string` + +GetValue returns the Value field if non-nil, zero value otherwise. + +### GetValueOk + +`func (o *DtoUpdateAnnotationRequest) GetValueOk() (*string, bool)` + +GetValueOk returns a tuple with the Value field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetValue + +`func (o *DtoUpdateAnnotationRequest) SetValue(v string)` + +SetValue sets Value field to given value. + +### HasValue + +`func (o *DtoUpdateAnnotationRequest) HasValue() bool` + +HasValue returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/sdk/go/docs/HandlersMeResponse.md b/sdk/go/docs/HandlersMeResponse.md index e80293b..ae0e138 100644 --- a/sdk/go/docs/HandlersMeResponse.md +++ b/sdk/go/docs/HandlersMeResponse.md @@ -9,6 +9,7 @@ Name | Type | Description | Notes **DisplayName** | Pointer to **string** | | [optional] **Emails** | Pointer to [**[]ModelsUserEmail**](ModelsUserEmail.md) | | [optional] **Id** | Pointer to **string** | example: 3fa85f64-5717-4562-b3fc-2c963f66afa6 | [optional] +**IsAdmin** | Pointer to **bool** | | [optional] **IsDisabled** | Pointer to **bool** | | [optional] **Organizations** | Pointer to [**[]ModelsOrganization**](ModelsOrganization.md) | | [optional] **PrimaryEmail** | Pointer to **string** | | [optional] @@ -158,6 +159,31 @@ SetId sets Id field to given value. HasId returns a boolean if a field has been set. +### GetIsAdmin + +`func (o *HandlersMeResponse) GetIsAdmin() bool` + +GetIsAdmin returns the IsAdmin field if non-nil, zero value otherwise. + +### GetIsAdminOk + +`func (o *HandlersMeResponse) GetIsAdminOk() (*bool, bool)` + +GetIsAdminOk returns a tuple with the IsAdmin field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetIsAdmin + +`func (o *HandlersMeResponse) SetIsAdmin(v bool)` + +SetIsAdmin sets IsAdmin field to given value. + +### HasIsAdmin + +`func (o *HandlersMeResponse) HasIsAdmin() bool` + +HasIsAdmin returns a boolean if a field has been set. + ### GetIsDisabled `func (o *HandlersMeResponse) GetIsDisabled() bool` diff --git a/sdk/go/docs/ModelsUser.md b/sdk/go/docs/ModelsUser.md index d74bb67..fe5d5d1 100644 --- a/sdk/go/docs/ModelsUser.md +++ b/sdk/go/docs/ModelsUser.md @@ -8,6 +8,7 @@ Name | Type | Description | Notes **CreatedAt** | Pointer to **time.Time** | | [optional] **DisplayName** | Pointer to **string** | | [optional] **Id** | Pointer to **string** | example: 3fa85f64-5717-4562-b3fc-2c963f66afa6 | [optional] +**IsAdmin** | Pointer to **bool** | | [optional] **IsDisabled** | Pointer to **bool** | | [optional] **PrimaryEmail** | Pointer to **string** | | [optional] **UpdatedAt** | Pointer to **time.Time** | | [optional] @@ -131,6 +132,31 @@ SetId sets Id field to given value. HasId returns a boolean if a field has been set. +### GetIsAdmin + +`func (o *ModelsUser) GetIsAdmin() bool` + +GetIsAdmin returns the IsAdmin field if non-nil, zero value otherwise. + +### GetIsAdminOk + +`func (o *ModelsUser) GetIsAdminOk() (*bool, bool)` + +GetIsAdminOk returns a tuple with the IsAdmin field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetIsAdmin + +`func (o *ModelsUser) SetIsAdmin(v bool)` + +SetIsAdmin sets IsAdmin field to given value. + +### HasIsAdmin + +`func (o *ModelsUser) HasIsAdmin() bool` + +HasIsAdmin returns a boolean if a field has been set. + ### GetIsDisabled `func (o *ModelsUser) GetIsDisabled() bool` diff --git a/sdk/go/model_dto_create_annotation_request.go b/sdk/go/model_dto_create_annotation_request.go new file mode 100644 index 0000000..d70efd6 --- /dev/null +++ b/sdk/go/model_dto_create_annotation_request.go @@ -0,0 +1,160 @@ +/* +AutoGlue API + +API for managing K3s clusters across cloud providers + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package autoglue + +import ( + "encoding/json" +) + +// checks if the DtoCreateAnnotationRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &DtoCreateAnnotationRequest{} + +// DtoCreateAnnotationRequest struct for DtoCreateAnnotationRequest +type DtoCreateAnnotationRequest struct { + Key *string `json:"key,omitempty"` + Value *string `json:"value,omitempty"` +} + +// NewDtoCreateAnnotationRequest instantiates a new DtoCreateAnnotationRequest object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewDtoCreateAnnotationRequest() *DtoCreateAnnotationRequest { + this := DtoCreateAnnotationRequest{} + return &this +} + +// NewDtoCreateAnnotationRequestWithDefaults instantiates a new DtoCreateAnnotationRequest object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewDtoCreateAnnotationRequestWithDefaults() *DtoCreateAnnotationRequest { + this := DtoCreateAnnotationRequest{} + return &this +} + +// GetKey returns the Key field value if set, zero value otherwise. +func (o *DtoCreateAnnotationRequest) GetKey() string { + if o == nil || IsNil(o.Key) { + var ret string + return ret + } + return *o.Key +} + +// GetKeyOk returns a tuple with the Key field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoCreateAnnotationRequest) GetKeyOk() (*string, bool) { + if o == nil || IsNil(o.Key) { + return nil, false + } + return o.Key, true +} + +// HasKey returns a boolean if a field has been set. +func (o *DtoCreateAnnotationRequest) HasKey() bool { + if o != nil && !IsNil(o.Key) { + return true + } + + return false +} + +// SetKey gets a reference to the given string and assigns it to the Key field. +func (o *DtoCreateAnnotationRequest) SetKey(v string) { + o.Key = &v +} + +// GetValue returns the Value field value if set, zero value otherwise. +func (o *DtoCreateAnnotationRequest) GetValue() string { + if o == nil || IsNil(o.Value) { + var ret string + return ret + } + return *o.Value +} + +// GetValueOk returns a tuple with the Value field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoCreateAnnotationRequest) GetValueOk() (*string, bool) { + if o == nil || IsNil(o.Value) { + return nil, false + } + return o.Value, true +} + +// HasValue returns a boolean if a field has been set. +func (o *DtoCreateAnnotationRequest) HasValue() bool { + if o != nil && !IsNil(o.Value) { + return true + } + + return false +} + +// SetValue gets a reference to the given string and assigns it to the Value field. +func (o *DtoCreateAnnotationRequest) SetValue(v string) { + o.Value = &v +} + +func (o DtoCreateAnnotationRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o DtoCreateAnnotationRequest) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Key) { + toSerialize["key"] = o.Key + } + if !IsNil(o.Value) { + toSerialize["value"] = o.Value + } + return toSerialize, nil +} + +type NullableDtoCreateAnnotationRequest struct { + value *DtoCreateAnnotationRequest + isSet bool +} + +func (v NullableDtoCreateAnnotationRequest) Get() *DtoCreateAnnotationRequest { + return v.value +} + +func (v *NullableDtoCreateAnnotationRequest) Set(val *DtoCreateAnnotationRequest) { + v.value = val + v.isSet = true +} + +func (v NullableDtoCreateAnnotationRequest) IsSet() bool { + return v.isSet +} + +func (v *NullableDtoCreateAnnotationRequest) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableDtoCreateAnnotationRequest(val *DtoCreateAnnotationRequest) *NullableDtoCreateAnnotationRequest { + return &NullableDtoCreateAnnotationRequest{value: val, isSet: true} +} + +func (v NullableDtoCreateAnnotationRequest) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableDtoCreateAnnotationRequest) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/sdk/go/model_dto_job.go b/sdk/go/model_dto_job.go new file mode 100644 index 0000000..971ad80 --- /dev/null +++ b/sdk/go/model_dto_job.go @@ -0,0 +1,495 @@ +/* +AutoGlue API + +API for managing K3s clusters across cloud providers + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package autoglue + +import ( + "encoding/json" +) + +// checks if the DtoJob type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &DtoJob{} + +// DtoJob struct for DtoJob +type DtoJob struct { + // example: 0 + Attempts *int32 `json:"attempts,omitempty"` + // example: 2025-11-04T09:30:00Z + CreatedAt *string `json:"created_at,omitempty"` + // example: 01HF7SZK8Z8WG1M3J7S2Z8M2N6 + Id *string `json:"id,omitempty"` + // example: dial tcp: i/o timeout + LastError *string `json:"last_error,omitempty"` + // example: 3 + MaxAttempts *int32 `json:"max_attempts,omitempty"` + // arbitrary JSON payload + Payload map[string]interface{} `json:"payload,omitempty"` + // example: default + Queue *string `json:"queue,omitempty"` + // example: 2025-11-05T08:00:00Z + RunAt *string `json:"run_at,omitempty"` + // enum: queued,running,succeeded,failed,canceled,retrying,scheduled example: queued + Status *DtoJobStatus `json:"status,omitempty"` + // example: email.send + Type *string `json:"type,omitempty"` + // example: 2025-11-04T09:31:00Z + UpdatedAt *string `json:"updated_at,omitempty"` +} + +// NewDtoJob instantiates a new DtoJob object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewDtoJob() *DtoJob { + this := DtoJob{} + return &this +} + +// NewDtoJobWithDefaults instantiates a new DtoJob object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewDtoJobWithDefaults() *DtoJob { + this := DtoJob{} + return &this +} + +// GetAttempts returns the Attempts field value if set, zero value otherwise. +func (o *DtoJob) GetAttempts() int32 { + if o == nil || IsNil(o.Attempts) { + var ret int32 + return ret + } + return *o.Attempts +} + +// GetAttemptsOk returns a tuple with the Attempts field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetAttemptsOk() (*int32, bool) { + if o == nil || IsNil(o.Attempts) { + return nil, false + } + return o.Attempts, true +} + +// HasAttempts returns a boolean if a field has been set. +func (o *DtoJob) HasAttempts() bool { + if o != nil && !IsNil(o.Attempts) { + return true + } + + return false +} + +// SetAttempts gets a reference to the given int32 and assigns it to the Attempts field. +func (o *DtoJob) SetAttempts(v int32) { + o.Attempts = &v +} + +// GetCreatedAt returns the CreatedAt field value if set, zero value otherwise. +func (o *DtoJob) GetCreatedAt() string { + if o == nil || IsNil(o.CreatedAt) { + var ret string + return ret + } + return *o.CreatedAt +} + +// GetCreatedAtOk returns a tuple with the CreatedAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetCreatedAtOk() (*string, bool) { + if o == nil || IsNil(o.CreatedAt) { + return nil, false + } + return o.CreatedAt, true +} + +// HasCreatedAt returns a boolean if a field has been set. +func (o *DtoJob) HasCreatedAt() bool { + if o != nil && !IsNil(o.CreatedAt) { + return true + } + + return false +} + +// SetCreatedAt gets a reference to the given string and assigns it to the CreatedAt field. +func (o *DtoJob) SetCreatedAt(v string) { + o.CreatedAt = &v +} + +// GetId returns the Id field value if set, zero value otherwise. +func (o *DtoJob) GetId() string { + if o == nil || IsNil(o.Id) { + var ret string + return ret + } + return *o.Id +} + +// GetIdOk returns a tuple with the Id field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetIdOk() (*string, bool) { + if o == nil || IsNil(o.Id) { + return nil, false + } + return o.Id, true +} + +// HasId returns a boolean if a field has been set. +func (o *DtoJob) HasId() bool { + if o != nil && !IsNil(o.Id) { + return true + } + + return false +} + +// SetId gets a reference to the given string and assigns it to the Id field. +func (o *DtoJob) SetId(v string) { + o.Id = &v +} + +// GetLastError returns the LastError field value if set, zero value otherwise. +func (o *DtoJob) GetLastError() string { + if o == nil || IsNil(o.LastError) { + var ret string + return ret + } + return *o.LastError +} + +// GetLastErrorOk returns a tuple with the LastError field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetLastErrorOk() (*string, bool) { + if o == nil || IsNil(o.LastError) { + return nil, false + } + return o.LastError, true +} + +// HasLastError returns a boolean if a field has been set. +func (o *DtoJob) HasLastError() bool { + if o != nil && !IsNil(o.LastError) { + return true + } + + return false +} + +// SetLastError gets a reference to the given string and assigns it to the LastError field. +func (o *DtoJob) SetLastError(v string) { + o.LastError = &v +} + +// GetMaxAttempts returns the MaxAttempts field value if set, zero value otherwise. +func (o *DtoJob) GetMaxAttempts() int32 { + if o == nil || IsNil(o.MaxAttempts) { + var ret int32 + return ret + } + return *o.MaxAttempts +} + +// GetMaxAttemptsOk returns a tuple with the MaxAttempts field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetMaxAttemptsOk() (*int32, bool) { + if o == nil || IsNil(o.MaxAttempts) { + return nil, false + } + return o.MaxAttempts, true +} + +// HasMaxAttempts returns a boolean if a field has been set. +func (o *DtoJob) HasMaxAttempts() bool { + if o != nil && !IsNil(o.MaxAttempts) { + return true + } + + return false +} + +// SetMaxAttempts gets a reference to the given int32 and assigns it to the MaxAttempts field. +func (o *DtoJob) SetMaxAttempts(v int32) { + o.MaxAttempts = &v +} + +// GetPayload returns the Payload field value if set, zero value otherwise. +func (o *DtoJob) GetPayload() map[string]interface{} { + if o == nil || IsNil(o.Payload) { + var ret map[string]interface{} + return ret + } + return o.Payload +} + +// GetPayloadOk returns a tuple with the Payload field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetPayloadOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.Payload) { + return map[string]interface{}{}, false + } + return o.Payload, true +} + +// HasPayload returns a boolean if a field has been set. +func (o *DtoJob) HasPayload() bool { + if o != nil && !IsNil(o.Payload) { + return true + } + + return false +} + +// SetPayload gets a reference to the given map[string]interface{} and assigns it to the Payload field. +func (o *DtoJob) SetPayload(v map[string]interface{}) { + o.Payload = v +} + +// GetQueue returns the Queue field value if set, zero value otherwise. +func (o *DtoJob) GetQueue() string { + if o == nil || IsNil(o.Queue) { + var ret string + return ret + } + return *o.Queue +} + +// GetQueueOk returns a tuple with the Queue field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetQueueOk() (*string, bool) { + if o == nil || IsNil(o.Queue) { + return nil, false + } + return o.Queue, true +} + +// HasQueue returns a boolean if a field has been set. +func (o *DtoJob) HasQueue() bool { + if o != nil && !IsNil(o.Queue) { + return true + } + + return false +} + +// SetQueue gets a reference to the given string and assigns it to the Queue field. +func (o *DtoJob) SetQueue(v string) { + o.Queue = &v +} + +// GetRunAt returns the RunAt field value if set, zero value otherwise. +func (o *DtoJob) GetRunAt() string { + if o == nil || IsNil(o.RunAt) { + var ret string + return ret + } + return *o.RunAt +} + +// GetRunAtOk returns a tuple with the RunAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetRunAtOk() (*string, bool) { + if o == nil || IsNil(o.RunAt) { + return nil, false + } + return o.RunAt, true +} + +// HasRunAt returns a boolean if a field has been set. +func (o *DtoJob) HasRunAt() bool { + if o != nil && !IsNil(o.RunAt) { + return true + } + + return false +} + +// SetRunAt gets a reference to the given string and assigns it to the RunAt field. +func (o *DtoJob) SetRunAt(v string) { + o.RunAt = &v +} + +// GetStatus returns the Status field value if set, zero value otherwise. +func (o *DtoJob) GetStatus() DtoJobStatus { + if o == nil || IsNil(o.Status) { + var ret DtoJobStatus + return ret + } + return *o.Status +} + +// GetStatusOk returns a tuple with the Status field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetStatusOk() (*DtoJobStatus, bool) { + if o == nil || IsNil(o.Status) { + return nil, false + } + return o.Status, true +} + +// HasStatus returns a boolean if a field has been set. +func (o *DtoJob) HasStatus() bool { + if o != nil && !IsNil(o.Status) { + return true + } + + return false +} + +// SetStatus gets a reference to the given DtoJobStatus and assigns it to the Status field. +func (o *DtoJob) SetStatus(v DtoJobStatus) { + o.Status = &v +} + +// GetType returns the Type field value if set, zero value otherwise. +func (o *DtoJob) GetType() string { + if o == nil || IsNil(o.Type) { + var ret string + return ret + } + return *o.Type +} + +// GetTypeOk returns a tuple with the Type field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetTypeOk() (*string, bool) { + if o == nil || IsNil(o.Type) { + return nil, false + } + return o.Type, true +} + +// HasType returns a boolean if a field has been set. +func (o *DtoJob) HasType() bool { + if o != nil && !IsNil(o.Type) { + return true + } + + return false +} + +// SetType gets a reference to the given string and assigns it to the Type field. +func (o *DtoJob) SetType(v string) { + o.Type = &v +} + +// GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise. +func (o *DtoJob) GetUpdatedAt() string { + if o == nil || IsNil(o.UpdatedAt) { + var ret string + return ret + } + return *o.UpdatedAt +} + +// GetUpdatedAtOk returns a tuple with the UpdatedAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoJob) GetUpdatedAtOk() (*string, bool) { + if o == nil || IsNil(o.UpdatedAt) { + return nil, false + } + return o.UpdatedAt, true +} + +// HasUpdatedAt returns a boolean if a field has been set. +func (o *DtoJob) HasUpdatedAt() bool { + if o != nil && !IsNil(o.UpdatedAt) { + return true + } + + return false +} + +// SetUpdatedAt gets a reference to the given string and assigns it to the UpdatedAt field. +func (o *DtoJob) SetUpdatedAt(v string) { + o.UpdatedAt = &v +} + +func (o DtoJob) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o DtoJob) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Attempts) { + toSerialize["attempts"] = o.Attempts + } + if !IsNil(o.CreatedAt) { + toSerialize["created_at"] = o.CreatedAt + } + if !IsNil(o.Id) { + toSerialize["id"] = o.Id + } + if !IsNil(o.LastError) { + toSerialize["last_error"] = o.LastError + } + if !IsNil(o.MaxAttempts) { + toSerialize["max_attempts"] = o.MaxAttempts + } + if !IsNil(o.Payload) { + toSerialize["payload"] = o.Payload + } + if !IsNil(o.Queue) { + toSerialize["queue"] = o.Queue + } + if !IsNil(o.RunAt) { + toSerialize["run_at"] = o.RunAt + } + if !IsNil(o.Status) { + toSerialize["status"] = o.Status + } + if !IsNil(o.Type) { + toSerialize["type"] = o.Type + } + if !IsNil(o.UpdatedAt) { + toSerialize["updated_at"] = o.UpdatedAt + } + return toSerialize, nil +} + +type NullableDtoJob struct { + value *DtoJob + isSet bool +} + +func (v NullableDtoJob) Get() *DtoJob { + return v.value +} + +func (v *NullableDtoJob) Set(val *DtoJob) { + v.value = val + v.isSet = true +} + +func (v NullableDtoJob) IsSet() bool { + return v.isSet +} + +func (v *NullableDtoJob) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableDtoJob(val *DtoJob) *NullableDtoJob { + return &NullableDtoJob{value: val, isSet: true} +} + +func (v NullableDtoJob) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableDtoJob) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/sdk/go/model_dto_job_status.go b/sdk/go/model_dto_job_status.go new file mode 100644 index 0000000..6575858 --- /dev/null +++ b/sdk/go/model_dto_job_status.go @@ -0,0 +1,120 @@ +/* +AutoGlue API + +API for managing K3s clusters across cloud providers + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package autoglue + +import ( + "encoding/json" + "fmt" +) + +// DtoJobStatus the model 'DtoJobStatus' +type DtoJobStatus string + +// List of dto.JobStatus +const ( + StatusQueued DtoJobStatus = "queued" + StatusRunning DtoJobStatus = "running" + StatusSucceeded DtoJobStatus = "succeeded" + StatusFailed DtoJobStatus = "failed" + StatusCanceled DtoJobStatus = "canceled" + StatusRetrying DtoJobStatus = "retrying" + StatusScheduled DtoJobStatus = "scheduled" +) + +// All allowed values of DtoJobStatus enum +var AllowedDtoJobStatusEnumValues = []DtoJobStatus{ + "queued", + "running", + "succeeded", + "failed", + "canceled", + "retrying", + "scheduled", +} + +func (v *DtoJobStatus) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := DtoJobStatus(value) + for _, existing := range AllowedDtoJobStatusEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid DtoJobStatus", value) +} + +// NewDtoJobStatusFromValue returns a pointer to a valid DtoJobStatus +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewDtoJobStatusFromValue(v string) (*DtoJobStatus, error) { + ev := DtoJobStatus(v) + if ev.IsValid() { + return &ev, nil + } else { + return nil, fmt.Errorf("invalid value '%v' for DtoJobStatus: valid values are %v", v, AllowedDtoJobStatusEnumValues) + } +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v DtoJobStatus) IsValid() bool { + for _, existing := range AllowedDtoJobStatusEnumValues { + if existing == v { + return true + } + } + return false +} + +// Ptr returns reference to dto.JobStatus value +func (v DtoJobStatus) Ptr() *DtoJobStatus { + return &v +} + +type NullableDtoJobStatus struct { + value *DtoJobStatus + isSet bool +} + +func (v NullableDtoJobStatus) Get() *DtoJobStatus { + return v.value +} + +func (v *NullableDtoJobStatus) Set(val *DtoJobStatus) { + v.value = val + v.isSet = true +} + +func (v NullableDtoJobStatus) IsSet() bool { + return v.isSet +} + +func (v *NullableDtoJobStatus) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableDtoJobStatus(val *DtoJobStatus) *NullableDtoJobStatus { + return &NullableDtoJobStatus{value: val, isSet: true} +} + +func (v NullableDtoJobStatus) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableDtoJobStatus) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/sdk/go/model_dto_page_job.go b/sdk/go/model_dto_page_job.go new file mode 100644 index 0000000..5271a99 --- /dev/null +++ b/sdk/go/model_dto_page_job.go @@ -0,0 +1,235 @@ +/* +AutoGlue API + +API for managing K3s clusters across cloud providers + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package autoglue + +import ( + "encoding/json" +) + +// checks if the DtoPageJob type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &DtoPageJob{} + +// DtoPageJob struct for DtoPageJob +type DtoPageJob struct { + Items []DtoJob `json:"items,omitempty"` + // example: 1 + Page *int32 `json:"page,omitempty"` + // example: 25 + PageSize *int32 `json:"page_size,omitempty"` + // example: 120 + Total *int32 `json:"total,omitempty"` +} + +// NewDtoPageJob instantiates a new DtoPageJob object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewDtoPageJob() *DtoPageJob { + this := DtoPageJob{} + return &this +} + +// NewDtoPageJobWithDefaults instantiates a new DtoPageJob object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewDtoPageJobWithDefaults() *DtoPageJob { + this := DtoPageJob{} + return &this +} + +// GetItems returns the Items field value if set, zero value otherwise. +func (o *DtoPageJob) GetItems() []DtoJob { + if o == nil || IsNil(o.Items) { + var ret []DtoJob + return ret + } + return o.Items +} + +// GetItemsOk returns a tuple with the Items field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoPageJob) GetItemsOk() ([]DtoJob, bool) { + if o == nil || IsNil(o.Items) { + return nil, false + } + return o.Items, true +} + +// HasItems returns a boolean if a field has been set. +func (o *DtoPageJob) HasItems() bool { + if o != nil && !IsNil(o.Items) { + return true + } + + return false +} + +// SetItems gets a reference to the given []DtoJob and assigns it to the Items field. +func (o *DtoPageJob) SetItems(v []DtoJob) { + o.Items = v +} + +// GetPage returns the Page field value if set, zero value otherwise. +func (o *DtoPageJob) GetPage() int32 { + if o == nil || IsNil(o.Page) { + var ret int32 + return ret + } + return *o.Page +} + +// GetPageOk returns a tuple with the Page field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoPageJob) GetPageOk() (*int32, bool) { + if o == nil || IsNil(o.Page) { + return nil, false + } + return o.Page, true +} + +// HasPage returns a boolean if a field has been set. +func (o *DtoPageJob) HasPage() bool { + if o != nil && !IsNil(o.Page) { + return true + } + + return false +} + +// SetPage gets a reference to the given int32 and assigns it to the Page field. +func (o *DtoPageJob) SetPage(v int32) { + o.Page = &v +} + +// GetPageSize returns the PageSize field value if set, zero value otherwise. +func (o *DtoPageJob) GetPageSize() int32 { + if o == nil || IsNil(o.PageSize) { + var ret int32 + return ret + } + return *o.PageSize +} + +// GetPageSizeOk returns a tuple with the PageSize field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoPageJob) GetPageSizeOk() (*int32, bool) { + if o == nil || IsNil(o.PageSize) { + return nil, false + } + return o.PageSize, true +} + +// HasPageSize returns a boolean if a field has been set. +func (o *DtoPageJob) HasPageSize() bool { + if o != nil && !IsNil(o.PageSize) { + return true + } + + return false +} + +// SetPageSize gets a reference to the given int32 and assigns it to the PageSize field. +func (o *DtoPageJob) SetPageSize(v int32) { + o.PageSize = &v +} + +// GetTotal returns the Total field value if set, zero value otherwise. +func (o *DtoPageJob) GetTotal() int32 { + if o == nil || IsNil(o.Total) { + var ret int32 + return ret + } + return *o.Total +} + +// GetTotalOk returns a tuple with the Total field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoPageJob) GetTotalOk() (*int32, bool) { + if o == nil || IsNil(o.Total) { + return nil, false + } + return o.Total, true +} + +// HasTotal returns a boolean if a field has been set. +func (o *DtoPageJob) HasTotal() bool { + if o != nil && !IsNil(o.Total) { + return true + } + + return false +} + +// SetTotal gets a reference to the given int32 and assigns it to the Total field. +func (o *DtoPageJob) SetTotal(v int32) { + o.Total = &v +} + +func (o DtoPageJob) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o DtoPageJob) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Items) { + toSerialize["items"] = o.Items + } + if !IsNil(o.Page) { + toSerialize["page"] = o.Page + } + if !IsNil(o.PageSize) { + toSerialize["page_size"] = o.PageSize + } + if !IsNil(o.Total) { + toSerialize["total"] = o.Total + } + return toSerialize, nil +} + +type NullableDtoPageJob struct { + value *DtoPageJob + isSet bool +} + +func (v NullableDtoPageJob) Get() *DtoPageJob { + return v.value +} + +func (v *NullableDtoPageJob) Set(val *DtoPageJob) { + v.value = val + v.isSet = true +} + +func (v NullableDtoPageJob) IsSet() bool { + return v.isSet +} + +func (v *NullableDtoPageJob) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableDtoPageJob(val *DtoPageJob) *NullableDtoPageJob { + return &NullableDtoPageJob{value: val, isSet: true} +} + +func (v NullableDtoPageJob) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableDtoPageJob) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/sdk/go/model_dto_queue_info.go b/sdk/go/model_dto_queue_info.go new file mode 100644 index 0000000..7500cb6 --- /dev/null +++ b/sdk/go/model_dto_queue_info.go @@ -0,0 +1,273 @@ +/* +AutoGlue API + +API for managing K3s clusters across cloud providers + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package autoglue + +import ( + "encoding/json" +) + +// checks if the DtoQueueInfo type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &DtoQueueInfo{} + +// DtoQueueInfo struct for DtoQueueInfo +type DtoQueueInfo struct { + // example: 5 + Failed *int32 `json:"failed,omitempty"` + // example: default + Name *string `json:"name,omitempty"` + // example: 42 + Pending *int32 `json:"pending,omitempty"` + // example: 3 + Running *int32 `json:"running,omitempty"` + // example: 7 + Scheduled *int32 `json:"scheduled,omitempty"` +} + +// NewDtoQueueInfo instantiates a new DtoQueueInfo object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewDtoQueueInfo() *DtoQueueInfo { + this := DtoQueueInfo{} + return &this +} + +// NewDtoQueueInfoWithDefaults instantiates a new DtoQueueInfo object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewDtoQueueInfoWithDefaults() *DtoQueueInfo { + this := DtoQueueInfo{} + return &this +} + +// GetFailed returns the Failed field value if set, zero value otherwise. +func (o *DtoQueueInfo) GetFailed() int32 { + if o == nil || IsNil(o.Failed) { + var ret int32 + return ret + } + return *o.Failed +} + +// GetFailedOk returns a tuple with the Failed field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoQueueInfo) GetFailedOk() (*int32, bool) { + if o == nil || IsNil(o.Failed) { + return nil, false + } + return o.Failed, true +} + +// HasFailed returns a boolean if a field has been set. +func (o *DtoQueueInfo) HasFailed() bool { + if o != nil && !IsNil(o.Failed) { + return true + } + + return false +} + +// SetFailed gets a reference to the given int32 and assigns it to the Failed field. +func (o *DtoQueueInfo) SetFailed(v int32) { + o.Failed = &v +} + +// GetName returns the Name field value if set, zero value otherwise. +func (o *DtoQueueInfo) GetName() string { + if o == nil || IsNil(o.Name) { + var ret string + return ret + } + return *o.Name +} + +// GetNameOk returns a tuple with the Name field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoQueueInfo) GetNameOk() (*string, bool) { + if o == nil || IsNil(o.Name) { + return nil, false + } + return o.Name, true +} + +// HasName returns a boolean if a field has been set. +func (o *DtoQueueInfo) HasName() bool { + if o != nil && !IsNil(o.Name) { + return true + } + + return false +} + +// SetName gets a reference to the given string and assigns it to the Name field. +func (o *DtoQueueInfo) SetName(v string) { + o.Name = &v +} + +// GetPending returns the Pending field value if set, zero value otherwise. +func (o *DtoQueueInfo) GetPending() int32 { + if o == nil || IsNil(o.Pending) { + var ret int32 + return ret + } + return *o.Pending +} + +// GetPendingOk returns a tuple with the Pending field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoQueueInfo) GetPendingOk() (*int32, bool) { + if o == nil || IsNil(o.Pending) { + return nil, false + } + return o.Pending, true +} + +// HasPending returns a boolean if a field has been set. +func (o *DtoQueueInfo) HasPending() bool { + if o != nil && !IsNil(o.Pending) { + return true + } + + return false +} + +// SetPending gets a reference to the given int32 and assigns it to the Pending field. +func (o *DtoQueueInfo) SetPending(v int32) { + o.Pending = &v +} + +// GetRunning returns the Running field value if set, zero value otherwise. +func (o *DtoQueueInfo) GetRunning() int32 { + if o == nil || IsNil(o.Running) { + var ret int32 + return ret + } + return *o.Running +} + +// GetRunningOk returns a tuple with the Running field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoQueueInfo) GetRunningOk() (*int32, bool) { + if o == nil || IsNil(o.Running) { + return nil, false + } + return o.Running, true +} + +// HasRunning returns a boolean if a field has been set. +func (o *DtoQueueInfo) HasRunning() bool { + if o != nil && !IsNil(o.Running) { + return true + } + + return false +} + +// SetRunning gets a reference to the given int32 and assigns it to the Running field. +func (o *DtoQueueInfo) SetRunning(v int32) { + o.Running = &v +} + +// GetScheduled returns the Scheduled field value if set, zero value otherwise. +func (o *DtoQueueInfo) GetScheduled() int32 { + if o == nil || IsNil(o.Scheduled) { + var ret int32 + return ret + } + return *o.Scheduled +} + +// GetScheduledOk returns a tuple with the Scheduled field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoQueueInfo) GetScheduledOk() (*int32, bool) { + if o == nil || IsNil(o.Scheduled) { + return nil, false + } + return o.Scheduled, true +} + +// HasScheduled returns a boolean if a field has been set. +func (o *DtoQueueInfo) HasScheduled() bool { + if o != nil && !IsNil(o.Scheduled) { + return true + } + + return false +} + +// SetScheduled gets a reference to the given int32 and assigns it to the Scheduled field. +func (o *DtoQueueInfo) SetScheduled(v int32) { + o.Scheduled = &v +} + +func (o DtoQueueInfo) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o DtoQueueInfo) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Failed) { + toSerialize["failed"] = o.Failed + } + if !IsNil(o.Name) { + toSerialize["name"] = o.Name + } + if !IsNil(o.Pending) { + toSerialize["pending"] = o.Pending + } + if !IsNil(o.Running) { + toSerialize["running"] = o.Running + } + if !IsNil(o.Scheduled) { + toSerialize["scheduled"] = o.Scheduled + } + return toSerialize, nil +} + +type NullableDtoQueueInfo struct { + value *DtoQueueInfo + isSet bool +} + +func (v NullableDtoQueueInfo) Get() *DtoQueueInfo { + return v.value +} + +func (v *NullableDtoQueueInfo) Set(val *DtoQueueInfo) { + v.value = val + v.isSet = true +} + +func (v NullableDtoQueueInfo) IsSet() bool { + return v.isSet +} + +func (v *NullableDtoQueueInfo) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableDtoQueueInfo(val *DtoQueueInfo) *NullableDtoQueueInfo { + return &NullableDtoQueueInfo{value: val, isSet: true} +} + +func (v NullableDtoQueueInfo) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableDtoQueueInfo) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/sdk/go/model_dto_update_annotation_request.go b/sdk/go/model_dto_update_annotation_request.go new file mode 100644 index 0000000..458b1ac --- /dev/null +++ b/sdk/go/model_dto_update_annotation_request.go @@ -0,0 +1,160 @@ +/* +AutoGlue API + +API for managing K3s clusters across cloud providers + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package autoglue + +import ( + "encoding/json" +) + +// checks if the DtoUpdateAnnotationRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &DtoUpdateAnnotationRequest{} + +// DtoUpdateAnnotationRequest struct for DtoUpdateAnnotationRequest +type DtoUpdateAnnotationRequest struct { + Key *string `json:"key,omitempty"` + Value *string `json:"value,omitempty"` +} + +// NewDtoUpdateAnnotationRequest instantiates a new DtoUpdateAnnotationRequest object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewDtoUpdateAnnotationRequest() *DtoUpdateAnnotationRequest { + this := DtoUpdateAnnotationRequest{} + return &this +} + +// NewDtoUpdateAnnotationRequestWithDefaults instantiates a new DtoUpdateAnnotationRequest object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewDtoUpdateAnnotationRequestWithDefaults() *DtoUpdateAnnotationRequest { + this := DtoUpdateAnnotationRequest{} + return &this +} + +// GetKey returns the Key field value if set, zero value otherwise. +func (o *DtoUpdateAnnotationRequest) GetKey() string { + if o == nil || IsNil(o.Key) { + var ret string + return ret + } + return *o.Key +} + +// GetKeyOk returns a tuple with the Key field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoUpdateAnnotationRequest) GetKeyOk() (*string, bool) { + if o == nil || IsNil(o.Key) { + return nil, false + } + return o.Key, true +} + +// HasKey returns a boolean if a field has been set. +func (o *DtoUpdateAnnotationRequest) HasKey() bool { + if o != nil && !IsNil(o.Key) { + return true + } + + return false +} + +// SetKey gets a reference to the given string and assigns it to the Key field. +func (o *DtoUpdateAnnotationRequest) SetKey(v string) { + o.Key = &v +} + +// GetValue returns the Value field value if set, zero value otherwise. +func (o *DtoUpdateAnnotationRequest) GetValue() string { + if o == nil || IsNil(o.Value) { + var ret string + return ret + } + return *o.Value +} + +// GetValueOk returns a tuple with the Value field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DtoUpdateAnnotationRequest) GetValueOk() (*string, bool) { + if o == nil || IsNil(o.Value) { + return nil, false + } + return o.Value, true +} + +// HasValue returns a boolean if a field has been set. +func (o *DtoUpdateAnnotationRequest) HasValue() bool { + if o != nil && !IsNil(o.Value) { + return true + } + + return false +} + +// SetValue gets a reference to the given string and assigns it to the Value field. +func (o *DtoUpdateAnnotationRequest) SetValue(v string) { + o.Value = &v +} + +func (o DtoUpdateAnnotationRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o DtoUpdateAnnotationRequest) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Key) { + toSerialize["key"] = o.Key + } + if !IsNil(o.Value) { + toSerialize["value"] = o.Value + } + return toSerialize, nil +} + +type NullableDtoUpdateAnnotationRequest struct { + value *DtoUpdateAnnotationRequest + isSet bool +} + +func (v NullableDtoUpdateAnnotationRequest) Get() *DtoUpdateAnnotationRequest { + return v.value +} + +func (v *NullableDtoUpdateAnnotationRequest) Set(val *DtoUpdateAnnotationRequest) { + v.value = val + v.isSet = true +} + +func (v NullableDtoUpdateAnnotationRequest) IsSet() bool { + return v.isSet +} + +func (v *NullableDtoUpdateAnnotationRequest) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableDtoUpdateAnnotationRequest(val *DtoUpdateAnnotationRequest) *NullableDtoUpdateAnnotationRequest { + return &NullableDtoUpdateAnnotationRequest{value: val, isSet: true} +} + +func (v NullableDtoUpdateAnnotationRequest) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableDtoUpdateAnnotationRequest) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/sdk/go/model_handlers_me_response.go b/sdk/go/model_handlers_me_response.go index 8eaca86..79947de 100644 --- a/sdk/go/model_handlers_me_response.go +++ b/sdk/go/model_handlers_me_response.go @@ -26,6 +26,7 @@ type HandlersMeResponse struct { Emails []ModelsUserEmail `json:"emails,omitempty"` // example: 3fa85f64-5717-4562-b3fc-2c963f66afa6 Id *string `json:"id,omitempty"` + IsAdmin *bool `json:"is_admin,omitempty"` IsDisabled *bool `json:"is_disabled,omitempty"` Organizations []ModelsOrganization `json:"organizations,omitempty"` PrimaryEmail *string `json:"primary_email,omitempty"` @@ -209,6 +210,38 @@ func (o *HandlersMeResponse) SetId(v string) { o.Id = &v } +// GetIsAdmin returns the IsAdmin field value if set, zero value otherwise. +func (o *HandlersMeResponse) GetIsAdmin() bool { + if o == nil || IsNil(o.IsAdmin) { + var ret bool + return ret + } + return *o.IsAdmin +} + +// GetIsAdminOk returns a tuple with the IsAdmin field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *HandlersMeResponse) GetIsAdminOk() (*bool, bool) { + if o == nil || IsNil(o.IsAdmin) { + return nil, false + } + return o.IsAdmin, true +} + +// HasIsAdmin returns a boolean if a field has been set. +func (o *HandlersMeResponse) HasIsAdmin() bool { + if o != nil && !IsNil(o.IsAdmin) { + return true + } + + return false +} + +// SetIsAdmin gets a reference to the given bool and assigns it to the IsAdmin field. +func (o *HandlersMeResponse) SetIsAdmin(v bool) { + o.IsAdmin = &v +} + // GetIsDisabled returns the IsDisabled field value if set, zero value otherwise. func (o *HandlersMeResponse) GetIsDisabled() bool { if o == nil || IsNil(o.IsDisabled) { @@ -362,6 +395,9 @@ func (o HandlersMeResponse) ToMap() (map[string]interface{}, error) { if !IsNil(o.Id) { toSerialize["id"] = o.Id } + if !IsNil(o.IsAdmin) { + toSerialize["is_admin"] = o.IsAdmin + } if !IsNil(o.IsDisabled) { toSerialize["is_disabled"] = o.IsDisabled } diff --git a/sdk/go/model_models_user.go b/sdk/go/model_models_user.go index 07886e6..272811c 100644 --- a/sdk/go/model_models_user.go +++ b/sdk/go/model_models_user.go @@ -25,6 +25,7 @@ type ModelsUser struct { DisplayName *string `json:"display_name,omitempty"` // example: 3fa85f64-5717-4562-b3fc-2c963f66afa6 Id *string `json:"id,omitempty"` + IsAdmin *bool `json:"is_admin,omitempty"` IsDisabled *bool `json:"is_disabled,omitempty"` PrimaryEmail *string `json:"primary_email,omitempty"` UpdatedAt *time.Time `json:"updated_at,omitempty"` @@ -175,6 +176,38 @@ func (o *ModelsUser) SetId(v string) { o.Id = &v } +// GetIsAdmin returns the IsAdmin field value if set, zero value otherwise. +func (o *ModelsUser) GetIsAdmin() bool { + if o == nil || IsNil(o.IsAdmin) { + var ret bool + return ret + } + return *o.IsAdmin +} + +// GetIsAdminOk returns a tuple with the IsAdmin field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ModelsUser) GetIsAdminOk() (*bool, bool) { + if o == nil || IsNil(o.IsAdmin) { + return nil, false + } + return o.IsAdmin, true +} + +// HasIsAdmin returns a boolean if a field has been set. +func (o *ModelsUser) HasIsAdmin() bool { + if o != nil && !IsNil(o.IsAdmin) { + return true + } + + return false +} + +// SetIsAdmin gets a reference to the given bool and assigns it to the IsAdmin field. +func (o *ModelsUser) SetIsAdmin(v bool) { + o.IsAdmin = &v +} + // GetIsDisabled returns the IsDisabled field value if set, zero value otherwise. func (o *ModelsUser) GetIsDisabled() bool { if o == nil || IsNil(o.IsDisabled) { @@ -293,6 +326,9 @@ func (o ModelsUser) ToMap() (map[string]interface{}, error) { if !IsNil(o.Id) { toSerialize["id"] = o.Id } + if !IsNil(o.IsAdmin) { + toSerialize["is_admin"] = o.IsAdmin + } if !IsNil(o.IsDisabled) { toSerialize["is_disabled"] = o.IsDisabled } diff --git a/sdk/go/test/api_annotations_test.go b/sdk/go/test/api_annotations_test.go index 2e42a73..1750cb1 100644 --- a/sdk/go/test/api_annotations_test.go +++ b/sdk/go/test/api_annotations_test.go @@ -22,6 +22,32 @@ func Test_autoglue_AnnotationsAPIService(t *testing.T) { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) + t.Run("Test AnnotationsAPIService CreateAnnotation", func(t *testing.T) { + + t.Skip("skip test") // remove to run test + + resp, httpRes, err := apiClient.AnnotationsAPI.CreateAnnotation(context.Background()).Execute() + + require.Nil(t, err) + require.NotNil(t, resp) + assert.Equal(t, 200, httpRes.StatusCode) + + }) + + t.Run("Test AnnotationsAPIService DeleteAnnotation", func(t *testing.T) { + + t.Skip("skip test") // remove to run test + + var id string + + resp, httpRes, err := apiClient.AnnotationsAPI.DeleteAnnotation(context.Background(), id).Execute() + + require.Nil(t, err) + require.NotNil(t, resp) + assert.Equal(t, 200, httpRes.StatusCode) + + }) + t.Run("Test AnnotationsAPIService GetAnnotation", func(t *testing.T) { t.Skip("skip test") // remove to run test @@ -48,4 +74,18 @@ func Test_autoglue_AnnotationsAPIService(t *testing.T) { }) + t.Run("Test AnnotationsAPIService UpdateAnnotation", func(t *testing.T) { + + t.Skip("skip test") // remove to run test + + var id string + + resp, httpRes, err := apiClient.AnnotationsAPI.UpdateAnnotation(context.Background(), id).Execute() + + require.Nil(t, err) + require.NotNil(t, resp) + assert.Equal(t, 200, httpRes.StatusCode) + + }) + } diff --git a/sdk/go/test/api_archer_admin_test.go b/sdk/go/test/api_archer_admin_test.go new file mode 100644 index 0000000..af08b4a --- /dev/null +++ b/sdk/go/test/api_archer_admin_test.go @@ -0,0 +1,89 @@ +/* +AutoGlue API + +Testing ArcherAdminAPIService + +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); + +package autoglue + +import ( + "context" + openapiclient "github.com/glueops/autoglue-sdk-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "testing" +) + +func Test_autoglue_ArcherAdminAPIService(t *testing.T) { + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + + t.Run("Test ArcherAdminAPIService AdminCancelArcherJob", func(t *testing.T) { + + t.Skip("skip test") // remove to run test + + var id string + + resp, httpRes, err := apiClient.ArcherAdminAPI.AdminCancelArcherJob(context.Background(), id).Execute() + + require.Nil(t, err) + require.NotNil(t, resp) + assert.Equal(t, 200, httpRes.StatusCode) + + }) + + t.Run("Test ArcherAdminAPIService AdminEnqueueArcherJob", func(t *testing.T) { + + t.Skip("skip test") // remove to run test + + resp, httpRes, err := apiClient.ArcherAdminAPI.AdminEnqueueArcherJob(context.Background()).Execute() + + require.Nil(t, err) + require.NotNil(t, resp) + assert.Equal(t, 200, httpRes.StatusCode) + + }) + + t.Run("Test ArcherAdminAPIService AdminListArcherJobs", func(t *testing.T) { + + t.Skip("skip test") // remove to run test + + resp, httpRes, err := apiClient.ArcherAdminAPI.AdminListArcherJobs(context.Background()).Execute() + + require.Nil(t, err) + require.NotNil(t, resp) + assert.Equal(t, 200, httpRes.StatusCode) + + }) + + t.Run("Test ArcherAdminAPIService AdminListArcherQueues", func(t *testing.T) { + + t.Skip("skip test") // remove to run test + + resp, httpRes, err := apiClient.ArcherAdminAPI.AdminListArcherQueues(context.Background()).Execute() + + require.Nil(t, err) + require.NotNil(t, resp) + assert.Equal(t, 200, httpRes.StatusCode) + + }) + + t.Run("Test ArcherAdminAPIService AdminRetryArcherJob", func(t *testing.T) { + + t.Skip("skip test") // remove to run test + + var id string + + resp, httpRes, err := apiClient.ArcherAdminAPI.AdminRetryArcherJob(context.Background(), id).Execute() + + require.Nil(t, err) + require.NotNil(t, resp) + assert.Equal(t, 200, httpRes.StatusCode) + + }) + +} diff --git a/sdk/ts/.openapi-generator/FILES b/sdk/ts/.openapi-generator/FILES index e5f4014..67c4490 100644 --- a/sdk/ts/.openapi-generator/FILES +++ b/sdk/ts/.openapi-generator/FILES @@ -3,23 +3,30 @@ .openapi-generator-ignore README.md docs/AnnotationsApi.md +docs/ArcherAdminApi.md docs/AuthApi.md docs/DtoAnnotationResponse.md docs/DtoAuthStartResponse.md +docs/DtoCreateAnnotationRequest.md docs/DtoCreateLabelRequest.md docs/DtoCreateSSHRequest.md docs/DtoCreateServerRequest.md docs/DtoCreateTaintRequest.md docs/DtoJWK.md docs/DtoJWKS.md +docs/DtoJob.md +docs/DtoJobStatus.md docs/DtoLabelResponse.md docs/DtoLogoutRequest.md +docs/DtoPageJob.md +docs/DtoQueueInfo.md docs/DtoRefreshRequest.md docs/DtoServerResponse.md docs/DtoSshResponse.md docs/DtoSshRevealResponse.md docs/DtoTaintResponse.md docs/DtoTokenPair.md +docs/DtoUpdateAnnotationRequest.md docs/DtoUpdateLabelRequest.md docs/DtoUpdateServerRequest.md docs/DtoUpdateTaintRequest.md @@ -49,6 +56,7 @@ docs/TaintsApi.md docs/UtilsErrorResponse.md package.json src/apis/AnnotationsApi.ts +src/apis/ArcherAdminApi.ts src/apis/AuthApi.ts src/apis/HealthApi.ts src/apis/LabelsApi.ts @@ -62,20 +70,26 @@ src/apis/index.ts src/index.ts src/models/DtoAnnotationResponse.ts src/models/DtoAuthStartResponse.ts +src/models/DtoCreateAnnotationRequest.ts src/models/DtoCreateLabelRequest.ts src/models/DtoCreateSSHRequest.ts src/models/DtoCreateServerRequest.ts src/models/DtoCreateTaintRequest.ts src/models/DtoJWK.ts src/models/DtoJWKS.ts +src/models/DtoJob.ts +src/models/DtoJobStatus.ts src/models/DtoLabelResponse.ts src/models/DtoLogoutRequest.ts +src/models/DtoPageJob.ts +src/models/DtoQueueInfo.ts src/models/DtoRefreshRequest.ts src/models/DtoServerResponse.ts src/models/DtoSshResponse.ts src/models/DtoSshRevealResponse.ts src/models/DtoTaintResponse.ts src/models/DtoTokenPair.ts +src/models/DtoUpdateAnnotationRequest.ts src/models/DtoUpdateLabelRequest.ts src/models/DtoUpdateServerRequest.ts src/models/DtoUpdateTaintRequest.ts diff --git a/sdk/ts/README.md b/sdk/ts/README.md index 641cdfb..762dd3c 100644 --- a/sdk/ts/README.md +++ b/sdk/ts/README.md @@ -13,8 +13,11 @@ npm install @glueops/autoglue-sdk-go --save Next, try it out. ```ts -import { Configuration, AnnotationsApi } from "@glueops/autoglue-sdk-go"; -import type { GetAnnotationRequest } from "@glueops/autoglue-sdk-go"; +import { + Configuration, + AnnotationsApi, +} from '@glueops/autoglue-sdk-go'; +import type { CreateAnnotationRequest } from '@glueops/autoglue-sdk-go'; async function example() { console.log("🚀 Testing @glueops/autoglue-sdk-go SDK..."); @@ -29,16 +32,14 @@ async function example() { const api = new AnnotationsApi(config); const body = { - // string | Annotation ID (UUID) - id: id_example, + // DtoCreateAnnotationRequest | Annotation payload + body: ..., // string | Organization UUID (optional) xOrgID: xOrgID_example, - // string | Optional: node_pools (optional) - include: include_example, - } satisfies GetAnnotationRequest; + } satisfies CreateAnnotationRequest; try { - const data = await api.getAnnotation(body); + const data = await api.createAnnotation(body); console.log(data); } catch (error) { console.error(error); @@ -55,71 +56,85 @@ example().catch(console.error); All URIs are relative to _http://localhost:8080/api/v1_ -| Class | Method | HTTP request | Description | -| ---------------- | ---------------------------------------------------------------------- | --------------------------------------- | ----------------------------------------------- | -| _AnnotationsApi_ | [**getAnnotation**](docs/AnnotationsApi.md#getannotation) | **GET** /annotations/{id} | Get annotation by ID (org scoped) | -| _AnnotationsApi_ | [**listAnnotations**](docs/AnnotationsApi.md#listannotations) | **GET** /annotations | List annotations (org scoped) | -| _AuthApi_ | [**authCallback**](docs/AuthApi.md#authcallback) | **GET** /auth/{provider}/callback | Handle social login callback | -| _AuthApi_ | [**authStart**](docs/AuthApi.md#authstart) | **POST** /auth/{provider}/start | Begin social login | -| _AuthApi_ | [**getJWKS**](docs/AuthApi.md#getjwks) | **GET** /.well-known/jwks.json | Get JWKS | -| _AuthApi_ | [**logout**](docs/AuthApi.md#logout) | **POST** /auth/logout | Revoke refresh token family (logout everywhere) | -| _AuthApi_ | [**refresh**](docs/AuthApi.md#refresh) | **POST** /auth/refresh | Rotate refresh token | -| _HealthApi_ | [**healthCheckOperationId**](docs/HealthApi.md#healthcheckoperationid) | **GET** /healthz | Basic health check | -| _LabelsApi_ | [**createLabel**](docs/LabelsApi.md#createlabel) | **POST** /labels | Create label (org scoped) | -| _LabelsApi_ | [**deleteLabel**](docs/LabelsApi.md#deletelabel) | **DELETE** /labels/{id} | Delete label (org scoped) | -| _LabelsApi_ | [**getLabel**](docs/LabelsApi.md#getlabel) | **GET** /labels/{id} | Get label by ID (org scoped) | -| _LabelsApi_ | [**listLabels**](docs/LabelsApi.md#listlabels) | **GET** /labels | List node labels (org scoped) | -| _LabelsApi_ | [**updateLabel**](docs/LabelsApi.md#updatelabel) | **PATCH** /labels/{id} | Update label (org scoped) | -| _MeApi_ | [**getMe**](docs/MeApi.md#getme) | **GET** /me | Get current user profile | -| _MeApi_ | [**updateMe**](docs/MeApi.md#updateme) | **PATCH** /me | Update current user profile | -| _MeAPIKeysApi_ | [**createUserAPIKey**](docs/MeAPIKeysApi.md#createuserapikey) | **POST** /me/api-keys | Create a new user API key | -| _MeAPIKeysApi_ | [**deleteUserAPIKey**](docs/MeAPIKeysApi.md#deleteuserapikey) | **DELETE** /me/api-keys/{id} | Delete a user API key | -| _MeAPIKeysApi_ | [**listUserAPIKeys**](docs/MeAPIKeysApi.md#listuserapikeys) | **GET** /me/api-keys | List my API keys | -| _OrgsApi_ | [**addOrUpdateMember**](docs/OrgsApi.md#addorupdatemember) | **POST** /orgs/{id}/members | Add or update a member (owner/admin) | -| _OrgsApi_ | [**createOrg**](docs/OrgsApi.md#createorg) | **POST** /orgs | Create organization | -| _OrgsApi_ | [**createOrgKey**](docs/OrgsApi.md#createorgkey) | **POST** /orgs/{id}/api-keys | Create org key/secret pair (owner/admin) | -| _OrgsApi_ | [**deleteOrg**](docs/OrgsApi.md#deleteorg) | **DELETE** /orgs/{id} | Delete organization (owner) | -| _OrgsApi_ | [**deleteOrgKey**](docs/OrgsApi.md#deleteorgkey) | **DELETE** /orgs/{id}/api-keys/{key_id} | Delete org key (owner/admin) | -| _OrgsApi_ | [**getOrg**](docs/OrgsApi.md#getorg) | **GET** /orgs/{id} | Get organization | -| _OrgsApi_ | [**listMembers**](docs/OrgsApi.md#listmembers) | **GET** /orgs/{id}/members | List members in org | -| _OrgsApi_ | [**listMyOrgs**](docs/OrgsApi.md#listmyorgs) | **GET** /orgs | List organizations I belong to | -| _OrgsApi_ | [**listOrgKeys**](docs/OrgsApi.md#listorgkeys) | **GET** /orgs/{id}/api-keys | List org-scoped API keys (no secrets) | -| _OrgsApi_ | [**removeMember**](docs/OrgsApi.md#removemember) | **DELETE** /orgs/{id}/members/{user_id} | Remove a member (owner/admin) | -| _OrgsApi_ | [**updateOrg**](docs/OrgsApi.md#updateorg) | **PATCH** /orgs/{id} | Update organization (owner/admin) | -| _ServersApi_ | [**createServer**](docs/ServersApi.md#createserver) | **POST** /servers | Create server (org scoped) | -| _ServersApi_ | [**deleteServer**](docs/ServersApi.md#deleteserver) | **DELETE** /servers/{id} | Delete server (org scoped) | -| _ServersApi_ | [**getServer**](docs/ServersApi.md#getserver) | **GET** /servers/{id} | Get server by ID (org scoped) | -| _ServersApi_ | [**listServers**](docs/ServersApi.md#listservers) | **GET** /servers | List servers (org scoped) | -| _ServersApi_ | [**updateServer**](docs/ServersApi.md#updateserver) | **PATCH** /servers/{id} | Update server (org scoped) | -| _SshApi_ | [**createSSHKey**](docs/SshApi.md#createsshkey) | **POST** /ssh | Create ssh keypair (org scoped) | -| _SshApi_ | [**deleteSSHKey**](docs/SshApi.md#deletesshkey) | **DELETE** /ssh/{id} | Delete ssh keypair (org scoped) | -| _SshApi_ | [**downloadSSHKey**](docs/SshApi.md#downloadsshkey) | **GET** /ssh/{id}/download | Download ssh key files by ID (org scoped) | -| _SshApi_ | [**getSSHKey**](docs/SshApi.md#getsshkey) | **GET** /ssh/{id} | Get ssh key by ID (org scoped) | -| _SshApi_ | [**listPublicSshKeys**](docs/SshApi.md#listpublicsshkeys) | **GET** /ssh | List ssh keys (org scoped) | -| _TaintsApi_ | [**createTaint**](docs/TaintsApi.md#createtaint) | **POST** /taints | Create node taint (org scoped) | -| _TaintsApi_ | [**deleteTaint**](docs/TaintsApi.md#deletetaint) | **DELETE** /taints/{id} | Delete taint (org scoped) | -| _TaintsApi_ | [**getTaint**](docs/TaintsApi.md#gettaint) | **GET** /taints/{id} | Get node taint by ID (org scoped) | -| _TaintsApi_ | [**listTaints**](docs/TaintsApi.md#listtaints) | **GET** /taints | List node pool taints (org scoped) | -| _TaintsApi_ | [**updateTaint**](docs/TaintsApi.md#updatetaint) | **PATCH** /taints/{id} | Update node taint (org scoped) | +| Class | Method | HTTP request | Description | +| ---------------- | ------------------------------------------------------------------------- | --------------------------------------- | ----------------------------------------------- | +| _AnnotationsApi_ | [**createAnnotation**](docs/AnnotationsApi.md#createannotation) | **POST** /annotations | Create annotation (org scoped) | +| _AnnotationsApi_ | [**deleteAnnotation**](docs/AnnotationsApi.md#deleteannotation) | **DELETE** /annotations/{id} | Delete annotation (org scoped) | +| _AnnotationsApi_ | [**getAnnotation**](docs/AnnotationsApi.md#getannotation) | **GET** /annotations/{id} | Get annotation by ID (org scoped) | +| _AnnotationsApi_ | [**listAnnotations**](docs/AnnotationsApi.md#listannotations) | **GET** /annotations | List annotations (org scoped) | +| _AnnotationsApi_ | [**updateAnnotation**](docs/AnnotationsApi.md#updateannotation) | **PATCH** /annotations/{id} | Update annotation (org scoped) | +| _ArcherAdminApi_ | [**adminCancelArcherJob**](docs/ArcherAdminApi.md#admincancelarcherjob) | **POST** /admin/archer/jobs/{id}/cancel | Cancel an Archer job (admin) | +| _ArcherAdminApi_ | [**adminEnqueueArcherJob**](docs/ArcherAdminApi.md#adminenqueuearcherjob) | **POST** /admin/archer/jobs | Enqueue a new Archer job (admin) | +| _ArcherAdminApi_ | [**adminListArcherJobs**](docs/ArcherAdminApi.md#adminlistarcherjobs) | **GET** /admin/archer/jobs | List Archer jobs (admin) | +| _ArcherAdminApi_ | [**adminListArcherQueues**](docs/ArcherAdminApi.md#adminlistarcherqueues) | **GET** /admin/archer/queues | List Archer queues (admin) | +| _ArcherAdminApi_ | [**adminRetryArcherJob**](docs/ArcherAdminApi.md#adminretryarcherjob) | **POST** /admin/archer/jobs/{id}/retry | Retry a failed/canceled Archer job (admin) | +| _AuthApi_ | [**authCallback**](docs/AuthApi.md#authcallback) | **GET** /auth/{provider}/callback | Handle social login callback | +| _AuthApi_ | [**authStart**](docs/AuthApi.md#authstart) | **POST** /auth/{provider}/start | Begin social login | +| _AuthApi_ | [**getJWKS**](docs/AuthApi.md#getjwks) | **GET** /.well-known/jwks.json | Get JWKS | +| _AuthApi_ | [**logout**](docs/AuthApi.md#logout) | **POST** /auth/logout | Revoke refresh token family (logout everywhere) | +| _AuthApi_ | [**refresh**](docs/AuthApi.md#refresh) | **POST** /auth/refresh | Rotate refresh token | +| _HealthApi_ | [**healthCheckOperationId**](docs/HealthApi.md#healthcheckoperationid) | **GET** /healthz | Basic health check | +| _LabelsApi_ | [**createLabel**](docs/LabelsApi.md#createlabel) | **POST** /labels | Create label (org scoped) | +| _LabelsApi_ | [**deleteLabel**](docs/LabelsApi.md#deletelabel) | **DELETE** /labels/{id} | Delete label (org scoped) | +| _LabelsApi_ | [**getLabel**](docs/LabelsApi.md#getlabel) | **GET** /labels/{id} | Get label by ID (org scoped) | +| _LabelsApi_ | [**listLabels**](docs/LabelsApi.md#listlabels) | **GET** /labels | List node labels (org scoped) | +| _LabelsApi_ | [**updateLabel**](docs/LabelsApi.md#updatelabel) | **PATCH** /labels/{id} | Update label (org scoped) | +| _MeApi_ | [**getMe**](docs/MeApi.md#getme) | **GET** /me | Get current user profile | +| _MeApi_ | [**updateMe**](docs/MeApi.md#updateme) | **PATCH** /me | Update current user profile | +| _MeAPIKeysApi_ | [**createUserAPIKey**](docs/MeAPIKeysApi.md#createuserapikey) | **POST** /me/api-keys | Create a new user API key | +| _MeAPIKeysApi_ | [**deleteUserAPIKey**](docs/MeAPIKeysApi.md#deleteuserapikey) | **DELETE** /me/api-keys/{id} | Delete a user API key | +| _MeAPIKeysApi_ | [**listUserAPIKeys**](docs/MeAPIKeysApi.md#listuserapikeys) | **GET** /me/api-keys | List my API keys | +| _OrgsApi_ | [**addOrUpdateMember**](docs/OrgsApi.md#addorupdatemember) | **POST** /orgs/{id}/members | Add or update a member (owner/admin) | +| _OrgsApi_ | [**createOrg**](docs/OrgsApi.md#createorg) | **POST** /orgs | Create organization | +| _OrgsApi_ | [**createOrgKey**](docs/OrgsApi.md#createorgkey) | **POST** /orgs/{id}/api-keys | Create org key/secret pair (owner/admin) | +| _OrgsApi_ | [**deleteOrg**](docs/OrgsApi.md#deleteorg) | **DELETE** /orgs/{id} | Delete organization (owner) | +| _OrgsApi_ | [**deleteOrgKey**](docs/OrgsApi.md#deleteorgkey) | **DELETE** /orgs/{id}/api-keys/{key_id} | Delete org key (owner/admin) | +| _OrgsApi_ | [**getOrg**](docs/OrgsApi.md#getorg) | **GET** /orgs/{id} | Get organization | +| _OrgsApi_ | [**listMembers**](docs/OrgsApi.md#listmembers) | **GET** /orgs/{id}/members | List members in org | +| _OrgsApi_ | [**listMyOrgs**](docs/OrgsApi.md#listmyorgs) | **GET** /orgs | List organizations I belong to | +| _OrgsApi_ | [**listOrgKeys**](docs/OrgsApi.md#listorgkeys) | **GET** /orgs/{id}/api-keys | List org-scoped API keys (no secrets) | +| _OrgsApi_ | [**removeMember**](docs/OrgsApi.md#removemember) | **DELETE** /orgs/{id}/members/{user_id} | Remove a member (owner/admin) | +| _OrgsApi_ | [**updateOrg**](docs/OrgsApi.md#updateorg) | **PATCH** /orgs/{id} | Update organization (owner/admin) | +| _ServersApi_ | [**createServer**](docs/ServersApi.md#createserver) | **POST** /servers | Create server (org scoped) | +| _ServersApi_ | [**deleteServer**](docs/ServersApi.md#deleteserver) | **DELETE** /servers/{id} | Delete server (org scoped) | +| _ServersApi_ | [**getServer**](docs/ServersApi.md#getserver) | **GET** /servers/{id} | Get server by ID (org scoped) | +| _ServersApi_ | [**listServers**](docs/ServersApi.md#listservers) | **GET** /servers | List servers (org scoped) | +| _ServersApi_ | [**updateServer**](docs/ServersApi.md#updateserver) | **PATCH** /servers/{id} | Update server (org scoped) | +| _SshApi_ | [**createSSHKey**](docs/SshApi.md#createsshkey) | **POST** /ssh | Create ssh keypair (org scoped) | +| _SshApi_ | [**deleteSSHKey**](docs/SshApi.md#deletesshkey) | **DELETE** /ssh/{id} | Delete ssh keypair (org scoped) | +| _SshApi_ | [**downloadSSHKey**](docs/SshApi.md#downloadsshkey) | **GET** /ssh/{id}/download | Download ssh key files by ID (org scoped) | +| _SshApi_ | [**getSSHKey**](docs/SshApi.md#getsshkey) | **GET** /ssh/{id} | Get ssh key by ID (org scoped) | +| _SshApi_ | [**listPublicSshKeys**](docs/SshApi.md#listpublicsshkeys) | **GET** /ssh | List ssh keys (org scoped) | +| _TaintsApi_ | [**createTaint**](docs/TaintsApi.md#createtaint) | **POST** /taints | Create node taint (org scoped) | +| _TaintsApi_ | [**deleteTaint**](docs/TaintsApi.md#deletetaint) | **DELETE** /taints/{id} | Delete taint (org scoped) | +| _TaintsApi_ | [**getTaint**](docs/TaintsApi.md#gettaint) | **GET** /taints/{id} | Get node taint by ID (org scoped) | +| _TaintsApi_ | [**listTaints**](docs/TaintsApi.md#listtaints) | **GET** /taints | List node pool taints (org scoped) | +| _TaintsApi_ | [**updateTaint**](docs/TaintsApi.md#updatetaint) | **PATCH** /taints/{id} | Update node taint (org scoped) | ### Models - [DtoAnnotationResponse](docs/DtoAnnotationResponse.md) - [DtoAuthStartResponse](docs/DtoAuthStartResponse.md) +- [DtoCreateAnnotationRequest](docs/DtoCreateAnnotationRequest.md) - [DtoCreateLabelRequest](docs/DtoCreateLabelRequest.md) - [DtoCreateSSHRequest](docs/DtoCreateSSHRequest.md) - [DtoCreateServerRequest](docs/DtoCreateServerRequest.md) - [DtoCreateTaintRequest](docs/DtoCreateTaintRequest.md) - [DtoJWK](docs/DtoJWK.md) - [DtoJWKS](docs/DtoJWKS.md) +- [DtoJob](docs/DtoJob.md) +- [DtoJobStatus](docs/DtoJobStatus.md) - [DtoLabelResponse](docs/DtoLabelResponse.md) - [DtoLogoutRequest](docs/DtoLogoutRequest.md) +- [DtoPageJob](docs/DtoPageJob.md) +- [DtoQueueInfo](docs/DtoQueueInfo.md) - [DtoRefreshRequest](docs/DtoRefreshRequest.md) - [DtoServerResponse](docs/DtoServerResponse.md) - [DtoSshResponse](docs/DtoSshResponse.md) - [DtoSshRevealResponse](docs/DtoSshRevealResponse.md) - [DtoTaintResponse](docs/DtoTaintResponse.md) - [DtoTokenPair](docs/DtoTokenPair.md) +- [DtoUpdateAnnotationRequest](docs/DtoUpdateAnnotationRequest.md) - [DtoUpdateLabelRequest](docs/DtoUpdateLabelRequest.md) - [DtoUpdateServerRequest](docs/DtoUpdateServerRequest.md) - [DtoUpdateTaintRequest](docs/DtoUpdateTaintRequest.md) diff --git a/sdk/ts/docs/AnnotationsApi.md b/sdk/ts/docs/AnnotationsApi.md index 2cce411..d2448df 100644 --- a/sdk/ts/docs/AnnotationsApi.md +++ b/sdk/ts/docs/AnnotationsApi.md @@ -2,14 +2,174 @@ All URIs are relative to _http://localhost:8080/api/v1_ -| Method | HTTP request | Description | -| -------------------------------------------------------- | ------------------------- | --------------------------------- | -| [**getAnnotation**](AnnotationsApi.md#getannotation) | **GET** /annotations/{id} | Get annotation by ID (org scoped) | -| [**listAnnotations**](AnnotationsApi.md#listannotations) | **GET** /annotations | List annotations (org scoped) | +| Method | HTTP request | Description | +| ---------------------------------------------------------- | ---------------------------- | --------------------------------- | +| [**createAnnotation**](AnnotationsApi.md#createannotation) | **POST** /annotations | Create annotation (org scoped) | +| [**deleteAnnotation**](AnnotationsApi.md#deleteannotation) | **DELETE** /annotations/{id} | Delete annotation (org scoped) | +| [**getAnnotation**](AnnotationsApi.md#getannotation) | **GET** /annotations/{id} | Get annotation by ID (org scoped) | +| [**listAnnotations**](AnnotationsApi.md#listannotations) | **GET** /annotations | List annotations (org scoped) | +| [**updateAnnotation**](AnnotationsApi.md#updateannotation) | **PATCH** /annotations/{id} | Update annotation (org scoped) | + +## createAnnotation + +> DtoAnnotationResponse createAnnotation(body, xOrgID) + +Create annotation (org scoped) + +Creates an annotation. + +### Example + +```ts +import { + Configuration, + AnnotationsApi, +} from '@glueops/autoglue-sdk-go'; +import type { CreateAnnotationRequest } from '@glueops/autoglue-sdk-go'; + +async function example() { + console.log("🚀 Testing @glueops/autoglue-sdk-go SDK..."); + const config = new Configuration({ + // To configure API key authorization: OrgKeyAuth + apiKey: "YOUR API KEY", + // To configure API key authorization: OrgSecretAuth + apiKey: "YOUR API KEY", + // To configure API key authorization: BearerAuth + apiKey: "YOUR API KEY", + }); + const api = new AnnotationsApi(config); + + const body = { + // DtoCreateAnnotationRequest | Annotation payload + body: ..., + // string | Organization UUID (optional) + xOrgID: xOrgID_example, + } satisfies CreateAnnotationRequest; + + try { + const data = await api.createAnnotation(body); + console.log(data); + } catch (error) { + console.error(error); + } +} + +// Run the test +example().catch(console.error); +``` + +### Parameters + +| Name | Type | Description | Notes | +| ---------- | ----------------------------------------------------------- | ------------------ | ------------------------------------ | +| **body** | [DtoCreateAnnotationRequest](DtoCreateAnnotationRequest.md) | Annotation payload | | +| **xOrgID** | `string` | Organization UUID | [Optional] [Defaults to `undefined`] | + +### Return type + +[**DtoAnnotationResponse**](DtoAnnotationResponse.md) + +### Authorization + +[OrgKeyAuth](../README.md#OrgKeyAuth), [OrgSecretAuth](../README.md#OrgSecretAuth), [BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: `application/json` +- **Accept**: `application/json` + +### HTTP response details + +| Status code | Description | Response headers | +| ----------- | ----------------------------- | ---------------- | +| **201** | Created | - | +| **400** | invalid json / missing fields | - | +| **401** | Unauthorized | - | +| **403** | organization required | - | +| **500** | create failed | - | + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) + +## deleteAnnotation + +> string deleteAnnotation(id, xOrgID) + +Delete annotation (org scoped) + +Permanently deletes the annotation. + +### Example + +```ts +import { Configuration, AnnotationsApi } from "@glueops/autoglue-sdk-go"; +import type { DeleteAnnotationRequest } from "@glueops/autoglue-sdk-go"; + +async function example() { + console.log("🚀 Testing @glueops/autoglue-sdk-go SDK..."); + const config = new Configuration({ + // To configure API key authorization: OrgKeyAuth + apiKey: "YOUR API KEY", + // To configure API key authorization: OrgSecretAuth + apiKey: "YOUR API KEY", + // To configure API key authorization: BearerAuth + apiKey: "YOUR API KEY", + }); + const api = new AnnotationsApi(config); + + const body = { + // string | Annotation ID (UUID) + id: id_example, + // string | Organization UUID (optional) + xOrgID: xOrgID_example, + } satisfies DeleteAnnotationRequest; + + try { + const data = await api.deleteAnnotation(body); + console.log(data); + } catch (error) { + console.error(error); + } +} + +// Run the test +example().catch(console.error); +``` + +### Parameters + +| Name | Type | Description | Notes | +| ---------- | -------- | -------------------- | ------------------------------------ | +| **id** | `string` | Annotation ID (UUID) | [Defaults to `undefined`] | +| **xOrgID** | `string` | Organization UUID | [Optional] [Defaults to `undefined`] | + +### Return type + +**string** + +### Authorization + +[OrgKeyAuth](../README.md#OrgKeyAuth), [OrgSecretAuth](../README.md#OrgSecretAuth), [BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: `application/json` + +### HTTP response details + +| Status code | Description | Response headers | +| ----------- | --------------------- | ---------------- | +| **204** | No Content | - | +| **400** | invalid id | - | +| **401** | Unauthorized | - | +| **403** | organization required | - | +| **500** | delete failed | - | + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) ## getAnnotation -> DtoAnnotationResponse getAnnotation(id, xOrgID, include) +> DtoAnnotationResponse getAnnotation(id, xOrgID) Get annotation by ID (org scoped) @@ -38,8 +198,6 @@ async function example() { id: id_example, // string | Organization UUID (optional) xOrgID: xOrgID_example, - // string | Optional: node_pools (optional) - include: include_example, } satisfies GetAnnotationRequest; try { @@ -56,11 +214,10 @@ example().catch(console.error); ### Parameters -| Name | Type | Description | Notes | -| ----------- | -------- | -------------------- | ------------------------------------ | -| **id** | `string` | Annotation ID (UUID) | [Defaults to `undefined`] | -| **xOrgID** | `string` | Organization UUID | [Optional] [Defaults to `undefined`] | -| **include** | `string` | Optional: node_pools | [Optional] [Defaults to `undefined`] | +| Name | Type | Description | Notes | +| ---------- | -------- | -------------------- | ------------------------------------ | +| **id** | `string` | Annotation ID (UUID) | [Defaults to `undefined`] | +| **xOrgID** | `string` | Organization UUID | [Optional] [Defaults to `undefined`] | ### Return type @@ -169,3 +326,87 @@ example().catch(console.error); | **500** | failed to list annotations | - | [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) + +## updateAnnotation + +> DtoAnnotationResponse updateAnnotation(id, body, xOrgID) + +Update annotation (org scoped) + +Partially update annotation fields. + +### Example + +```ts +import { + Configuration, + AnnotationsApi, +} from '@glueops/autoglue-sdk-go'; +import type { UpdateAnnotationRequest } from '@glueops/autoglue-sdk-go'; + +async function example() { + console.log("🚀 Testing @glueops/autoglue-sdk-go SDK..."); + const config = new Configuration({ + // To configure API key authorization: OrgKeyAuth + apiKey: "YOUR API KEY", + // To configure API key authorization: OrgSecretAuth + apiKey: "YOUR API KEY", + // To configure API key authorization: BearerAuth + apiKey: "YOUR API KEY", + }); + const api = new AnnotationsApi(config); + + const body = { + // string | Annotation ID (UUID) + id: id_example, + // DtoUpdateAnnotationRequest | Fields to update + body: ..., + // string | Organization UUID (optional) + xOrgID: xOrgID_example, + } satisfies UpdateAnnotationRequest; + + try { + const data = await api.updateAnnotation(body); + console.log(data); + } catch (error) { + console.error(error); + } +} + +// Run the test +example().catch(console.error); +``` + +### Parameters + +| Name | Type | Description | Notes | +| ---------- | ----------------------------------------------------------- | -------------------- | ------------------------------------ | +| **id** | `string` | Annotation ID (UUID) | [Defaults to `undefined`] | +| **body** | [DtoUpdateAnnotationRequest](DtoUpdateAnnotationRequest.md) | Fields to update | | +| **xOrgID** | `string` | Organization UUID | [Optional] [Defaults to `undefined`] | + +### Return type + +[**DtoAnnotationResponse**](DtoAnnotationResponse.md) + +### Authorization + +[OrgKeyAuth](../README.md#OrgKeyAuth), [OrgSecretAuth](../README.md#OrgSecretAuth), [BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: `application/json` +- **Accept**: `application/json` + +### HTTP response details + +| Status code | Description | Response headers | +| ----------- | ------------------------- | ---------------- | +| **200** | OK | - | +| **400** | invalid id / invalid json | - | +| **401** | Unauthorized | - | +| **403** | organization required | - | +| **404** | not found | - | +| **500** | update failed | - | + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) diff --git a/sdk/ts/docs/ArcherAdminApi.md b/sdk/ts/docs/ArcherAdminApi.md new file mode 100644 index 0000000..118c5b2 --- /dev/null +++ b/sdk/ts/docs/ArcherAdminApi.md @@ -0,0 +1,364 @@ +# ArcherAdminApi + +All URIs are relative to _http://localhost:8080/api/v1_ + +| Method | HTTP request | Description | +| -------------------------------------------------------------------- | --------------------------------------- | ------------------------------------------ | +| [**adminCancelArcherJob**](ArcherAdminApi.md#admincancelarcherjob) | **POST** /admin/archer/jobs/{id}/cancel | Cancel an Archer job (admin) | +| [**adminEnqueueArcherJob**](ArcherAdminApi.md#adminenqueuearcherjob) | **POST** /admin/archer/jobs | Enqueue a new Archer job (admin) | +| [**adminListArcherJobs**](ArcherAdminApi.md#adminlistarcherjobs) | **GET** /admin/archer/jobs | List Archer jobs (admin) | +| [**adminListArcherQueues**](ArcherAdminApi.md#adminlistarcherqueues) | **GET** /admin/archer/queues | List Archer queues (admin) | +| [**adminRetryArcherJob**](ArcherAdminApi.md#adminretryarcherjob) | **POST** /admin/archer/jobs/{id}/retry | Retry a failed/canceled Archer job (admin) | + +## adminCancelArcherJob + +> DtoJob adminCancelArcherJob(id) + +Cancel an Archer job (admin) + +Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill. + +### Example + +```ts +import { Configuration, ArcherAdminApi } from "@glueops/autoglue-sdk-go"; +import type { AdminCancelArcherJobRequest } from "@glueops/autoglue-sdk-go"; + +async function example() { + console.log("🚀 Testing @glueops/autoglue-sdk-go SDK..."); + const config = new Configuration({ + // To configure API key authorization: BearerAuth + apiKey: "YOUR API KEY", + }); + const api = new ArcherAdminApi(config); + + const body = { + // string | Job ID + id: id_example, + } satisfies AdminCancelArcherJobRequest; + + try { + const data = await api.adminCancelArcherJob(body); + console.log(data); + } catch (error) { + console.error(error); + } +} + +// Run the test +example().catch(console.error); +``` + +### Parameters + +| Name | Type | Description | Notes | +| ------ | -------- | ----------- | ------------------------- | +| **id** | `string` | Job ID | [Defaults to `undefined`] | + +### Return type + +[**DtoJob**](DtoJob.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: `application/json` + +### HTTP response details + +| Status code | Description | Response headers | +| ----------- | ------------------------------ | ---------------- | +| **200** | OK | - | +| **400** | invalid job or not cancellable | - | +| **401** | Unauthorized | - | +| **403** | forbidden | - | +| **404** | not found | - | + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) + +## adminEnqueueArcherJob + +> DtoJob adminEnqueueArcherJob(body) + +Enqueue a new Archer job (admin) + +Create a job immediately or schedule it for the future via `run_at`. + +### Example + +```ts +import { Configuration, ArcherAdminApi } from "@glueops/autoglue-sdk-go"; +import type { AdminEnqueueArcherJobRequest } from "@glueops/autoglue-sdk-go"; + +async function example() { + console.log("🚀 Testing @glueops/autoglue-sdk-go SDK..."); + const config = new Configuration({ + // To configure API key authorization: BearerAuth + apiKey: "YOUR API KEY", + }); + const api = new ArcherAdminApi(config); + + const body = { + // object | Job parameters + body: Object, + } satisfies AdminEnqueueArcherJobRequest; + + try { + const data = await api.adminEnqueueArcherJob(body); + console.log(data); + } catch (error) { + console.error(error); + } +} + +// Run the test +example().catch(console.error); +``` + +### Parameters + +| Name | Type | Description | Notes | +| -------- | -------- | -------------- | ----- | +| **body** | `object` | Job parameters | | + +### Return type + +[**DtoJob**](DtoJob.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: `application/json` +- **Accept**: `application/json` + +### HTTP response details + +| Status code | Description | Response headers | +| ----------- | ------------------------------ | ---------------- | +| **200** | OK | - | +| **400** | invalid json or missing fields | - | +| **401** | Unauthorized | - | +| **403** | forbidden | - | +| **500** | internal error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) + +## adminListArcherJobs + +> DtoPageJob adminListArcherJobs(status, queue, q, page, pageSize) + +List Archer jobs (admin) + +Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent). + +### Example + +```ts +import { Configuration, ArcherAdminApi } from "@glueops/autoglue-sdk-go"; +import type { AdminListArcherJobsRequest } from "@glueops/autoglue-sdk-go"; + +async function example() { + console.log("🚀 Testing @glueops/autoglue-sdk-go SDK..."); + const config = new Configuration({ + // To configure API key authorization: BearerAuth + apiKey: "YOUR API KEY", + }); + const api = new ArcherAdminApi(config); + + const body = { + // 'queued' | 'running' | 'succeeded' | 'failed' | 'canceled' | 'retrying' | 'scheduled' | Filter by status (optional) + status: status_example, + // string | Filter by queue name / worker name (optional) + queue: queue_example, + // string | Free-text search (optional) + q: q_example, + // number | Page number (optional) + page: 56, + // number | Items per page (optional) + pageSize: 56, + } satisfies AdminListArcherJobsRequest; + + try { + const data = await api.adminListArcherJobs(body); + console.log(data); + } catch (error) { + console.error(error); + } +} + +// Run the test +example().catch(console.error); +``` + +### Parameters + +| Name | Type | Description | Notes | +| ------------ | ------------------------------------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| **status** | `queued`, `running`, `succeeded`, `failed`, `canceled`, `retrying`, `scheduled` | Filter by status | [Optional] [Defaults to `undefined`] [Enum: queued, running, succeeded, failed, canceled, retrying, scheduled] | +| **queue** | `string` | Filter by queue name / worker name | [Optional] [Defaults to `undefined`] | +| **q** | `string` | Free-text search | [Optional] [Defaults to `undefined`] | +| **page** | `number` | Page number | [Optional] [Defaults to `1`] | +| **pageSize** | `number` | Items per page | [Optional] [Defaults to `25`] | + +### Return type + +[**DtoPageJob**](DtoPageJob.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: `application/json` + +### HTTP response details + +| Status code | Description | Response headers | +| ----------- | -------------- | ---------------- | +| **200** | OK | - | +| **401** | Unauthorized | - | +| **403** | forbidden | - | +| **500** | internal error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) + +## adminListArcherQueues + +> Array<DtoQueueInfo> adminListArcherQueues() + +List Archer queues (admin) + +Summary metrics per queue (pending, running, failed, scheduled). + +### Example + +```ts +import { Configuration, ArcherAdminApi } from "@glueops/autoglue-sdk-go"; +import type { AdminListArcherQueuesRequest } from "@glueops/autoglue-sdk-go"; + +async function example() { + console.log("🚀 Testing @glueops/autoglue-sdk-go SDK..."); + const config = new Configuration({ + // To configure API key authorization: BearerAuth + apiKey: "YOUR API KEY", + }); + const api = new ArcherAdminApi(config); + + try { + const data = await api.adminListArcherQueues(); + console.log(data); + } catch (error) { + console.error(error); + } +} + +// Run the test +example().catch(console.error); +``` + +### Parameters + +This endpoint does not need any parameter. + +### Return type + +[**Array<DtoQueueInfo>**](DtoQueueInfo.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: `application/json` + +### HTTP response details + +| Status code | Description | Response headers | +| ----------- | -------------- | ---------------- | +| **200** | OK | - | +| **401** | Unauthorized | - | +| **403** | forbidden | - | +| **500** | internal error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) + +## adminRetryArcherJob + +> DtoJob adminRetryArcherJob(id) + +Retry a failed/canceled Archer job (admin) + +Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one. + +### Example + +```ts +import { Configuration, ArcherAdminApi } from "@glueops/autoglue-sdk-go"; +import type { AdminRetryArcherJobRequest } from "@glueops/autoglue-sdk-go"; + +async function example() { + console.log("🚀 Testing @glueops/autoglue-sdk-go SDK..."); + const config = new Configuration({ + // To configure API key authorization: BearerAuth + apiKey: "YOUR API KEY", + }); + const api = new ArcherAdminApi(config); + + const body = { + // string | Job ID + id: id_example, + } satisfies AdminRetryArcherJobRequest; + + try { + const data = await api.adminRetryArcherJob(body); + console.log(data); + } catch (error) { + console.error(error); + } +} + +// Run the test +example().catch(console.error); +``` + +### Parameters + +| Name | Type | Description | Notes | +| ------ | -------- | ----------- | ------------------------- | +| **id** | `string` | Job ID | [Defaults to `undefined`] | + +### Return type + +[**DtoJob**](DtoJob.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: `application/json` + +### HTTP response details + +| Status code | Description | Response headers | +| ----------- | --------------------------- | ---------------- | +| **200** | OK | - | +| **400** | invalid job or not eligible | - | +| **401** | Unauthorized | - | +| **403** | forbidden | - | +| **404** | not found | - | + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) diff --git a/sdk/ts/docs/DtoCreateAnnotationRequest.md b/sdk/ts/docs/DtoCreateAnnotationRequest.md new file mode 100644 index 0000000..8c0e2da --- /dev/null +++ b/sdk/ts/docs/DtoCreateAnnotationRequest.md @@ -0,0 +1,32 @@ +# DtoCreateAnnotationRequest + +## Properties + +| Name | Type | +| ------- | ------ | +| `key` | string | +| `value` | string | + +## Example + +```typescript +import type { DtoCreateAnnotationRequest } from "@glueops/autoglue-sdk-go"; + +// TODO: Update the object below with actual values +const example = { + key: null, + value: null, +} satisfies DtoCreateAnnotationRequest; + +console.log(example); + +// Convert the instance to a JSON string +const exampleJSON: string = JSON.stringify(example); +console.log(exampleJSON); + +// Parse the JSON string back to an object +const exampleParsed = JSON.parse(exampleJSON) as DtoCreateAnnotationRequest; +console.log(exampleParsed); +``` + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) diff --git a/sdk/ts/docs/DtoJob.md b/sdk/ts/docs/DtoJob.md new file mode 100644 index 0000000..d7539b2 --- /dev/null +++ b/sdk/ts/docs/DtoJob.md @@ -0,0 +1,50 @@ +# DtoJob + +## Properties + +| Name | Type | +| -------------- | ------------------------------- | +| `attempts` | number | +| `created_at` | string | +| `id` | string | +| `last_error` | string | +| `max_attempts` | number | +| `payload` | object | +| `queue` | string | +| `run_at` | string | +| `status` | [DtoJobStatus](DtoJobStatus.md) | +| `type` | string | +| `updated_at` | string | + +## Example + +```typescript +import type { DtoJob } from "@glueops/autoglue-sdk-go"; + +// TODO: Update the object below with actual values +const example = { + attempts: null, + created_at: null, + id: null, + last_error: null, + max_attempts: null, + payload: null, + queue: null, + run_at: null, + status: null, + type: null, + updated_at: null, +} satisfies DtoJob; + +console.log(example); + +// Convert the instance to a JSON string +const exampleJSON: string = JSON.stringify(example); +console.log(exampleJSON); + +// Parse the JSON string back to an object +const exampleParsed = JSON.parse(exampleJSON) as DtoJob; +console.log(exampleParsed); +``` + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) diff --git a/sdk/ts/docs/DtoJobStatus.md b/sdk/ts/docs/DtoJobStatus.md new file mode 100644 index 0000000..09b2203 --- /dev/null +++ b/sdk/ts/docs/DtoJobStatus.md @@ -0,0 +1,27 @@ +# DtoJobStatus + +## Properties + +| Name | Type | +| ---- | ---- | + +## Example + +```typescript +import type { DtoJobStatus } from "@glueops/autoglue-sdk-go"; + +// TODO: Update the object below with actual values +const example = {} satisfies DtoJobStatus; + +console.log(example); + +// Convert the instance to a JSON string +const exampleJSON: string = JSON.stringify(example); +console.log(exampleJSON); + +// Parse the JSON string back to an object +const exampleParsed = JSON.parse(exampleJSON) as DtoJobStatus; +console.log(exampleParsed); +``` + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) diff --git a/sdk/ts/docs/DtoPageJob.md b/sdk/ts/docs/DtoPageJob.md new file mode 100644 index 0000000..82dc32d --- /dev/null +++ b/sdk/ts/docs/DtoPageJob.md @@ -0,0 +1,36 @@ +# DtoPageJob + +## Properties + +| Name | Type | +| ----------- | -------------------------------- | +| `items` | [Array<DtoJob>](DtoJob.md) | +| `page` | number | +| `page_size` | number | +| `total` | number | + +## Example + +```typescript +import type { DtoPageJob } from "@glueops/autoglue-sdk-go"; + +// TODO: Update the object below with actual values +const example = { + items: null, + page: null, + page_size: null, + total: null, +} satisfies DtoPageJob; + +console.log(example); + +// Convert the instance to a JSON string +const exampleJSON: string = JSON.stringify(example); +console.log(exampleJSON); + +// Parse the JSON string back to an object +const exampleParsed = JSON.parse(exampleJSON) as DtoPageJob; +console.log(exampleParsed); +``` + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) diff --git a/sdk/ts/docs/DtoQueueInfo.md b/sdk/ts/docs/DtoQueueInfo.md new file mode 100644 index 0000000..e582e86 --- /dev/null +++ b/sdk/ts/docs/DtoQueueInfo.md @@ -0,0 +1,38 @@ +# DtoQueueInfo + +## Properties + +| Name | Type | +| ----------- | ------ | +| `failed` | number | +| `name` | string | +| `pending` | number | +| `running` | number | +| `scheduled` | number | + +## Example + +```typescript +import type { DtoQueueInfo } from "@glueops/autoglue-sdk-go"; + +// TODO: Update the object below with actual values +const example = { + failed: null, + name: null, + pending: null, + running: null, + scheduled: null, +} satisfies DtoQueueInfo; + +console.log(example); + +// Convert the instance to a JSON string +const exampleJSON: string = JSON.stringify(example); +console.log(exampleJSON); + +// Parse the JSON string back to an object +const exampleParsed = JSON.parse(exampleJSON) as DtoQueueInfo; +console.log(exampleParsed); +``` + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) diff --git a/sdk/ts/docs/DtoUpdateAnnotationRequest.md b/sdk/ts/docs/DtoUpdateAnnotationRequest.md new file mode 100644 index 0000000..657e5a6 --- /dev/null +++ b/sdk/ts/docs/DtoUpdateAnnotationRequest.md @@ -0,0 +1,32 @@ +# DtoUpdateAnnotationRequest + +## Properties + +| Name | Type | +| ------- | ------ | +| `key` | string | +| `value` | string | + +## Example + +```typescript +import type { DtoUpdateAnnotationRequest } from "@glueops/autoglue-sdk-go"; + +// TODO: Update the object below with actual values +const example = { + key: null, + value: null, +} satisfies DtoUpdateAnnotationRequest; + +console.log(example); + +// Convert the instance to a JSON string +const exampleJSON: string = JSON.stringify(example); +console.log(exampleJSON); + +// Parse the JSON string back to an object +const exampleParsed = JSON.parse(exampleJSON) as DtoUpdateAnnotationRequest; +console.log(exampleParsed); +``` + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) diff --git a/sdk/ts/docs/HandlersMeResponse.md b/sdk/ts/docs/HandlersMeResponse.md index 46311f0..16dfb8a 100644 --- a/sdk/ts/docs/HandlersMeResponse.md +++ b/sdk/ts/docs/HandlersMeResponse.md @@ -9,6 +9,7 @@ | `display_name` | string | | `emails` | [Array<ModelsUserEmail>](ModelsUserEmail.md) | | `id` | string | +| `is_admin` | boolean | | `is_disabled` | boolean | | `organizations` | [Array<ModelsOrganization>](ModelsOrganization.md) | | `primary_email` | string | @@ -26,6 +27,7 @@ const example = { display_name: null, emails: null, id: null, + is_admin: null, is_disabled: null, organizations: null, primary_email: null, diff --git a/sdk/ts/docs/ModelsUser.md b/sdk/ts/docs/ModelsUser.md index ac06fd8..5a8a7c5 100644 --- a/sdk/ts/docs/ModelsUser.md +++ b/sdk/ts/docs/ModelsUser.md @@ -8,6 +8,7 @@ | `created_at` | Date | | `display_name` | string | | `id` | string | +| `is_admin` | boolean | | `is_disabled` | boolean | | `primary_email` | string | | `updated_at` | Date | @@ -23,6 +24,7 @@ const example = { created_at: null, display_name: null, id: null, + is_admin: null, is_disabled: null, primary_email: null, updated_at: null, diff --git a/sdk/ts/src/apis/AnnotationsApi.ts b/sdk/ts/src/apis/AnnotationsApi.ts index e7fb1c3..d0ac6ef 100644 --- a/sdk/ts/src/apis/AnnotationsApi.ts +++ b/sdk/ts/src/apis/AnnotationsApi.ts @@ -13,16 +13,33 @@ */ import * as runtime from "../runtime"; -import type { DtoAnnotationResponse } from "../models/index"; +import type { + DtoAnnotationResponse, + DtoCreateAnnotationRequest, + DtoUpdateAnnotationRequest, +} from "../models/index"; import { DtoAnnotationResponseFromJSON, DtoAnnotationResponseToJSON, + DtoCreateAnnotationRequestFromJSON, + DtoCreateAnnotationRequestToJSON, + DtoUpdateAnnotationRequestFromJSON, + DtoUpdateAnnotationRequestToJSON, } from "../models/index"; +export interface CreateAnnotationRequest { + body: DtoCreateAnnotationRequest; + xOrgID?: string; +} + +export interface DeleteAnnotationRequest { + id: string; + xOrgID?: string; +} + export interface GetAnnotationRequest { id: string; xOrgID?: string; - include?: string; } export interface ListAnnotationsRequest { @@ -32,10 +49,165 @@ export interface ListAnnotationsRequest { q?: string; } +export interface UpdateAnnotationRequest { + id: string; + body: DtoUpdateAnnotationRequest; + xOrgID?: string; +} + /** * */ export class AnnotationsApi extends runtime.BaseAPI { + /** + * Creates an annotation. + * Create annotation (org scoped) + */ + async createAnnotationRaw( + requestParameters: CreateAnnotationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise> { + if (requestParameters["body"] == null) { + throw new runtime.RequiredError( + "body", + 'Required parameter "body" was null or undefined when calling createAnnotation().', + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters["Content-Type"] = "application/json"; + + if (requestParameters["xOrgID"] != null) { + headerParameters["X-Org-ID"] = String(requestParameters["xOrgID"]); + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["X-ORG-KEY"] = + await this.configuration.apiKey("X-ORG-KEY"); // OrgKeyAuth authentication + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["X-ORG-SECRET"] = + await this.configuration.apiKey("X-ORG-SECRET"); // OrgSecretAuth authentication + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Authorization"] = + await this.configuration.apiKey("Authorization"); // BearerAuth authentication + } + + let urlPath = `/annotations`; + + const response = await this.request( + { + path: urlPath, + method: "POST", + headers: headerParameters, + query: queryParameters, + body: DtoCreateAnnotationRequestToJSON(requestParameters["body"]), + }, + initOverrides, + ); + + return new runtime.JSONApiResponse(response, (jsonValue) => + DtoAnnotationResponseFromJSON(jsonValue), + ); + } + + /** + * Creates an annotation. + * Create annotation (org scoped) + */ + async createAnnotation( + requestParameters: CreateAnnotationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise { + const response = await this.createAnnotationRaw( + requestParameters, + initOverrides, + ); + return await response.value(); + } + + /** + * Permanently deletes the annotation. + * Delete annotation (org scoped) + */ + async deleteAnnotationRaw( + requestParameters: DeleteAnnotationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise> { + if (requestParameters["id"] == null) { + throw new runtime.RequiredError( + "id", + 'Required parameter "id" was null or undefined when calling deleteAnnotation().', + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (requestParameters["xOrgID"] != null) { + headerParameters["X-Org-ID"] = String(requestParameters["xOrgID"]); + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["X-ORG-KEY"] = + await this.configuration.apiKey("X-ORG-KEY"); // OrgKeyAuth authentication + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["X-ORG-SECRET"] = + await this.configuration.apiKey("X-ORG-SECRET"); // OrgSecretAuth authentication + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Authorization"] = + await this.configuration.apiKey("Authorization"); // BearerAuth authentication + } + + let urlPath = `/annotations/{id}`; + urlPath = urlPath.replace( + `{${"id"}}`, + encodeURIComponent(String(requestParameters["id"])), + ); + + const response = await this.request( + { + path: urlPath, + method: "DELETE", + headers: headerParameters, + query: queryParameters, + }, + initOverrides, + ); + + if (this.isJsonMime(response.headers.get("content-type"))) { + return new runtime.JSONApiResponse(response); + } else { + return new runtime.TextApiResponse(response) as any; + } + } + + /** + * Permanently deletes the annotation. + * Delete annotation (org scoped) + */ + async deleteAnnotation( + requestParameters: DeleteAnnotationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise { + const response = await this.deleteAnnotationRaw( + requestParameters, + initOverrides, + ); + return await response.value(); + } + /** * Returns one annotation. Add `include=node_pools` to include node pools. * Get annotation by ID (org scoped) @@ -53,10 +225,6 @@ export class AnnotationsApi extends runtime.BaseAPI { const queryParameters: any = {}; - if (requestParameters["include"] != null) { - queryParameters["include"] = requestParameters["include"]; - } - const headerParameters: runtime.HTTPHeaders = {}; if (requestParameters["xOrgID"] != null) { @@ -188,4 +356,88 @@ export class AnnotationsApi extends runtime.BaseAPI { ); return await response.value(); } + + /** + * Partially update annotation fields. + * Update annotation (org scoped) + */ + async updateAnnotationRaw( + requestParameters: UpdateAnnotationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise> { + if (requestParameters["id"] == null) { + throw new runtime.RequiredError( + "id", + 'Required parameter "id" was null or undefined when calling updateAnnotation().', + ); + } + + if (requestParameters["body"] == null) { + throw new runtime.RequiredError( + "body", + 'Required parameter "body" was null or undefined when calling updateAnnotation().', + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters["Content-Type"] = "application/json"; + + if (requestParameters["xOrgID"] != null) { + headerParameters["X-Org-ID"] = String(requestParameters["xOrgID"]); + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["X-ORG-KEY"] = + await this.configuration.apiKey("X-ORG-KEY"); // OrgKeyAuth authentication + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["X-ORG-SECRET"] = + await this.configuration.apiKey("X-ORG-SECRET"); // OrgSecretAuth authentication + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Authorization"] = + await this.configuration.apiKey("Authorization"); // BearerAuth authentication + } + + let urlPath = `/annotations/{id}`; + urlPath = urlPath.replace( + `{${"id"}}`, + encodeURIComponent(String(requestParameters["id"])), + ); + + const response = await this.request( + { + path: urlPath, + method: "PATCH", + headers: headerParameters, + query: queryParameters, + body: DtoUpdateAnnotationRequestToJSON(requestParameters["body"]), + }, + initOverrides, + ); + + return new runtime.JSONApiResponse(response, (jsonValue) => + DtoAnnotationResponseFromJSON(jsonValue), + ); + } + + /** + * Partially update annotation fields. + * Update annotation (org scoped) + */ + async updateAnnotation( + requestParameters: UpdateAnnotationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise { + const response = await this.updateAnnotationRaw( + requestParameters, + initOverrides, + ); + return await response.value(); + } } diff --git a/sdk/ts/src/apis/ArcherAdminApi.ts b/sdk/ts/src/apis/ArcherAdminApi.ts new file mode 100644 index 0000000..af18344 --- /dev/null +++ b/sdk/ts/src/apis/ArcherAdminApi.ts @@ -0,0 +1,356 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * AutoGlue API + * API for managing K3s clusters across cloud providers + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import * as runtime from "../runtime"; +import type { DtoJob, DtoPageJob, DtoQueueInfo } from "../models/index"; +import { + DtoJobFromJSON, + DtoJobToJSON, + DtoPageJobFromJSON, + DtoPageJobToJSON, + DtoQueueInfoFromJSON, + DtoQueueInfoToJSON, +} from "../models/index"; + +export interface AdminCancelArcherJobRequest { + id: string; +} + +export interface AdminEnqueueArcherJobRequest { + body: object; +} + +export interface AdminListArcherJobsRequest { + status?: AdminListArcherJobsStatusEnum; + queue?: string; + q?: string; + page?: number; + pageSize?: number; +} + +export interface AdminRetryArcherJobRequest { + id: string; +} + +/** + * + */ +export class ArcherAdminApi extends runtime.BaseAPI { + /** + * Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill. + * Cancel an Archer job (admin) + */ + async adminCancelArcherJobRaw( + requestParameters: AdminCancelArcherJobRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise> { + if (requestParameters["id"] == null) { + throw new runtime.RequiredError( + "id", + 'Required parameter "id" was null or undefined when calling adminCancelArcherJob().', + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Authorization"] = + await this.configuration.apiKey("Authorization"); // BearerAuth authentication + } + + let urlPath = `/admin/archer/jobs/{id}/cancel`; + urlPath = urlPath.replace( + `{${"id"}}`, + encodeURIComponent(String(requestParameters["id"])), + ); + + const response = await this.request( + { + path: urlPath, + method: "POST", + headers: headerParameters, + query: queryParameters, + }, + initOverrides, + ); + + return new runtime.JSONApiResponse(response, (jsonValue) => + DtoJobFromJSON(jsonValue), + ); + } + + /** + * Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill. + * Cancel an Archer job (admin) + */ + async adminCancelArcherJob( + requestParameters: AdminCancelArcherJobRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise { + const response = await this.adminCancelArcherJobRaw( + requestParameters, + initOverrides, + ); + return await response.value(); + } + + /** + * Create a job immediately or schedule it for the future via `run_at`. + * Enqueue a new Archer job (admin) + */ + async adminEnqueueArcherJobRaw( + requestParameters: AdminEnqueueArcherJobRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise> { + if (requestParameters["body"] == null) { + throw new runtime.RequiredError( + "body", + 'Required parameter "body" was null or undefined when calling adminEnqueueArcherJob().', + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters["Content-Type"] = "application/json"; + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Authorization"] = + await this.configuration.apiKey("Authorization"); // BearerAuth authentication + } + + let urlPath = `/admin/archer/jobs`; + + const response = await this.request( + { + path: urlPath, + method: "POST", + headers: headerParameters, + query: queryParameters, + body: requestParameters["body"] as any, + }, + initOverrides, + ); + + return new runtime.JSONApiResponse(response, (jsonValue) => + DtoJobFromJSON(jsonValue), + ); + } + + /** + * Create a job immediately or schedule it for the future via `run_at`. + * Enqueue a new Archer job (admin) + */ + async adminEnqueueArcherJob( + requestParameters: AdminEnqueueArcherJobRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise { + const response = await this.adminEnqueueArcherJobRaw( + requestParameters, + initOverrides, + ); + return await response.value(); + } + + /** + * Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent). + * List Archer jobs (admin) + */ + async adminListArcherJobsRaw( + requestParameters: AdminListArcherJobsRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise> { + const queryParameters: any = {}; + + if (requestParameters["status"] != null) { + queryParameters["status"] = requestParameters["status"]; + } + + if (requestParameters["queue"] != null) { + queryParameters["queue"] = requestParameters["queue"]; + } + + if (requestParameters["q"] != null) { + queryParameters["q"] = requestParameters["q"]; + } + + if (requestParameters["page"] != null) { + queryParameters["page"] = requestParameters["page"]; + } + + if (requestParameters["pageSize"] != null) { + queryParameters["page_size"] = requestParameters["pageSize"]; + } + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Authorization"] = + await this.configuration.apiKey("Authorization"); // BearerAuth authentication + } + + let urlPath = `/admin/archer/jobs`; + + const response = await this.request( + { + path: urlPath, + method: "GET", + headers: headerParameters, + query: queryParameters, + }, + initOverrides, + ); + + return new runtime.JSONApiResponse(response, (jsonValue) => + DtoPageJobFromJSON(jsonValue), + ); + } + + /** + * Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent). + * List Archer jobs (admin) + */ + async adminListArcherJobs( + requestParameters: AdminListArcherJobsRequest = {}, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise { + const response = await this.adminListArcherJobsRaw( + requestParameters, + initOverrides, + ); + return await response.value(); + } + + /** + * Summary metrics per queue (pending, running, failed, scheduled). + * List Archer queues (admin) + */ + async adminListArcherQueuesRaw( + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise>> { + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Authorization"] = + await this.configuration.apiKey("Authorization"); // BearerAuth authentication + } + + let urlPath = `/admin/archer/queues`; + + const response = await this.request( + { + path: urlPath, + method: "GET", + headers: headerParameters, + query: queryParameters, + }, + initOverrides, + ); + + return new runtime.JSONApiResponse(response, (jsonValue) => + jsonValue.map(DtoQueueInfoFromJSON), + ); + } + + /** + * Summary metrics per queue (pending, running, failed, scheduled). + * List Archer queues (admin) + */ + async adminListArcherQueues( + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise> { + const response = await this.adminListArcherQueuesRaw(initOverrides); + return await response.value(); + } + + /** + * Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one. + * Retry a failed/canceled Archer job (admin) + */ + async adminRetryArcherJobRaw( + requestParameters: AdminRetryArcherJobRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise> { + if (requestParameters["id"] == null) { + throw new runtime.RequiredError( + "id", + 'Required parameter "id" was null or undefined when calling adminRetryArcherJob().', + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Authorization"] = + await this.configuration.apiKey("Authorization"); // BearerAuth authentication + } + + let urlPath = `/admin/archer/jobs/{id}/retry`; + urlPath = urlPath.replace( + `{${"id"}}`, + encodeURIComponent(String(requestParameters["id"])), + ); + + const response = await this.request( + { + path: urlPath, + method: "POST", + headers: headerParameters, + query: queryParameters, + }, + initOverrides, + ); + + return new runtime.JSONApiResponse(response, (jsonValue) => + DtoJobFromJSON(jsonValue), + ); + } + + /** + * Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one. + * Retry a failed/canceled Archer job (admin) + */ + async adminRetryArcherJob( + requestParameters: AdminRetryArcherJobRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise { + const response = await this.adminRetryArcherJobRaw( + requestParameters, + initOverrides, + ); + return await response.value(); + } +} + +/** + * @export + */ +export const AdminListArcherJobsStatusEnum = { + queued: "queued", + running: "running", + succeeded: "succeeded", + failed: "failed", + canceled: "canceled", + retrying: "retrying", + scheduled: "scheduled", +} as const; +export type AdminListArcherJobsStatusEnum = + (typeof AdminListArcherJobsStatusEnum)[keyof typeof AdminListArcherJobsStatusEnum]; diff --git a/sdk/ts/src/apis/index.ts b/sdk/ts/src/apis/index.ts index 9ce6288..47b4820 100644 --- a/sdk/ts/src/apis/index.ts +++ b/sdk/ts/src/apis/index.ts @@ -1,6 +1,7 @@ /* tslint:disable */ /* eslint-disable */ export * from "./AnnotationsApi"; +export * from "./ArcherAdminApi"; export * from "./AuthApi"; export * from "./HealthApi"; export * from "./LabelsApi"; diff --git a/sdk/ts/src/models/DtoCreateAnnotationRequest.ts b/sdk/ts/src/models/DtoCreateAnnotationRequest.ts new file mode 100644 index 0000000..805f0a8 --- /dev/null +++ b/sdk/ts/src/models/DtoCreateAnnotationRequest.ts @@ -0,0 +1,82 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * AutoGlue API + * API for managing K3s clusters across cloud providers + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from "../runtime"; +/** + * + * @export + * @interface DtoCreateAnnotationRequest + */ +export interface DtoCreateAnnotationRequest { + /** + * + * @type {string} + * @memberof DtoCreateAnnotationRequest + */ + key?: string; + /** + * + * @type {string} + * @memberof DtoCreateAnnotationRequest + */ + value?: string; +} + +/** + * Check if a given object implements the DtoCreateAnnotationRequest interface. + */ +export function instanceOfDtoCreateAnnotationRequest( + value: object, +): value is DtoCreateAnnotationRequest { + return true; +} + +export function DtoCreateAnnotationRequestFromJSON( + json: any, +): DtoCreateAnnotationRequest { + return DtoCreateAnnotationRequestFromJSONTyped(json, false); +} + +export function DtoCreateAnnotationRequestFromJSONTyped( + json: any, + ignoreDiscriminator: boolean, +): DtoCreateAnnotationRequest { + if (json == null) { + return json; + } + return { + key: json["key"] == null ? undefined : json["key"], + value: json["value"] == null ? undefined : json["value"], + }; +} + +export function DtoCreateAnnotationRequestToJSON( + json: any, +): DtoCreateAnnotationRequest { + return DtoCreateAnnotationRequestToJSONTyped(json, false); +} + +export function DtoCreateAnnotationRequestToJSONTyped( + value?: DtoCreateAnnotationRequest | null, + ignoreDiscriminator: boolean = false, +): any { + if (value == null) { + return value; + } + + return { + key: value["key"], + value: value["value"], + }; +} diff --git a/sdk/ts/src/models/DtoJob.ts b/sdk/ts/src/models/DtoJob.ts new file mode 100644 index 0000000..d3a4dea --- /dev/null +++ b/sdk/ts/src/models/DtoJob.ts @@ -0,0 +1,159 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * AutoGlue API + * API for managing K3s clusters across cloud providers + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from "../runtime"; +import type { DtoJobStatus } from "./DtoJobStatus"; +import { + DtoJobStatusFromJSON, + DtoJobStatusFromJSONTyped, + DtoJobStatusToJSON, + DtoJobStatusToJSONTyped, +} from "./DtoJobStatus"; + +/** + * + * @export + * @interface DtoJob + */ +export interface DtoJob { + /** + * example: 0 + * @type {number} + * @memberof DtoJob + */ + attempts?: number; + /** + * example: 2025-11-04T09:30:00Z + * @type {string} + * @memberof DtoJob + */ + created_at?: string; + /** + * example: 01HF7SZK8Z8WG1M3J7S2Z8M2N6 + * @type {string} + * @memberof DtoJob + */ + id?: string; + /** + * example: dial tcp: i/o timeout + * @type {string} + * @memberof DtoJob + */ + last_error?: string; + /** + * example: 3 + * @type {number} + * @memberof DtoJob + */ + max_attempts?: number; + /** + * arbitrary JSON payload + * @type {object} + * @memberof DtoJob + */ + payload?: object; + /** + * example: default + * @type {string} + * @memberof DtoJob + */ + queue?: string; + /** + * example: 2025-11-05T08:00:00Z + * @type {string} + * @memberof DtoJob + */ + run_at?: string; + /** + * enum: queued,running,succeeded,failed,canceled,retrying,scheduled + * example: queued + * @type {DtoJobStatus} + * @memberof DtoJob + */ + status?: DtoJobStatus; + /** + * example: email.send + * @type {string} + * @memberof DtoJob + */ + type?: string; + /** + * example: 2025-11-04T09:31:00Z + * @type {string} + * @memberof DtoJob + */ + updated_at?: string; +} + +/** + * Check if a given object implements the DtoJob interface. + */ +export function instanceOfDtoJob(value: object): value is DtoJob { + return true; +} + +export function DtoJobFromJSON(json: any): DtoJob { + return DtoJobFromJSONTyped(json, false); +} + +export function DtoJobFromJSONTyped( + json: any, + ignoreDiscriminator: boolean, +): DtoJob { + if (json == null) { + return json; + } + return { + attempts: json["attempts"] == null ? undefined : json["attempts"], + created_at: json["created_at"] == null ? undefined : json["created_at"], + id: json["id"] == null ? undefined : json["id"], + last_error: json["last_error"] == null ? undefined : json["last_error"], + max_attempts: + json["max_attempts"] == null ? undefined : json["max_attempts"], + payload: json["payload"] == null ? undefined : json["payload"], + queue: json["queue"] == null ? undefined : json["queue"], + run_at: json["run_at"] == null ? undefined : json["run_at"], + status: + json["status"] == null ? undefined : DtoJobStatusFromJSON(json["status"]), + type: json["type"] == null ? undefined : json["type"], + updated_at: json["updated_at"] == null ? undefined : json["updated_at"], + }; +} + +export function DtoJobToJSON(json: any): DtoJob { + return DtoJobToJSONTyped(json, false); +} + +export function DtoJobToJSONTyped( + value?: DtoJob | null, + ignoreDiscriminator: boolean = false, +): any { + if (value == null) { + return value; + } + + return { + attempts: value["attempts"], + created_at: value["created_at"], + id: value["id"], + last_error: value["last_error"], + max_attempts: value["max_attempts"], + payload: value["payload"], + queue: value["queue"], + run_at: value["run_at"], + status: DtoJobStatusToJSON(value["status"]), + type: value["type"], + updated_at: value["updated_at"], + }; +} diff --git a/sdk/ts/src/models/DtoJobStatus.ts b/sdk/ts/src/models/DtoJobStatus.ts new file mode 100644 index 0000000..1312a8c --- /dev/null +++ b/sdk/ts/src/models/DtoJobStatus.ts @@ -0,0 +1,61 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * AutoGlue API + * API for managing K3s clusters across cloud providers + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const DtoJobStatus = { + StatusQueued: "queued", + StatusRunning: "running", + StatusSucceeded: "succeeded", + StatusFailed: "failed", + StatusCanceled: "canceled", + StatusRetrying: "retrying", + StatusScheduled: "scheduled", +} as const; +export type DtoJobStatus = (typeof DtoJobStatus)[keyof typeof DtoJobStatus]; + +export function instanceOfDtoJobStatus(value: any): boolean { + for (const key in DtoJobStatus) { + if (Object.prototype.hasOwnProperty.call(DtoJobStatus, key)) { + if (DtoJobStatus[key as keyof typeof DtoJobStatus] === value) { + return true; + } + } + } + return false; +} + +export function DtoJobStatusFromJSON(json: any): DtoJobStatus { + return DtoJobStatusFromJSONTyped(json, false); +} + +export function DtoJobStatusFromJSONTyped( + json: any, + ignoreDiscriminator: boolean, +): DtoJobStatus { + return json as DtoJobStatus; +} + +export function DtoJobStatusToJSON(value?: DtoJobStatus | null): any { + return value as any; +} + +export function DtoJobStatusToJSONTyped( + value: any, + ignoreDiscriminator: boolean, +): DtoJobStatus { + return value as DtoJobStatus; +} diff --git a/sdk/ts/src/models/DtoPageJob.ts b/sdk/ts/src/models/DtoPageJob.ts new file mode 100644 index 0000000..4699e65 --- /dev/null +++ b/sdk/ts/src/models/DtoPageJob.ts @@ -0,0 +1,106 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * AutoGlue API + * API for managing K3s clusters across cloud providers + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from "../runtime"; +import type { DtoJob } from "./DtoJob"; +import { + DtoJobFromJSON, + DtoJobFromJSONTyped, + DtoJobToJSON, + DtoJobToJSONTyped, +} from "./DtoJob"; + +/** + * + * @export + * @interface DtoPageJob + */ +export interface DtoPageJob { + /** + * + * @type {Array} + * @memberof DtoPageJob + */ + items?: Array; + /** + * example: 1 + * @type {number} + * @memberof DtoPageJob + */ + page?: number; + /** + * example: 25 + * @type {number} + * @memberof DtoPageJob + */ + page_size?: number; + /** + * example: 120 + * @type {number} + * @memberof DtoPageJob + */ + total?: number; +} + +/** + * Check if a given object implements the DtoPageJob interface. + */ +export function instanceOfDtoPageJob(value: object): value is DtoPageJob { + return true; +} + +export function DtoPageJobFromJSON(json: any): DtoPageJob { + return DtoPageJobFromJSONTyped(json, false); +} + +export function DtoPageJobFromJSONTyped( + json: any, + ignoreDiscriminator: boolean, +): DtoPageJob { + if (json == null) { + return json; + } + return { + items: + json["items"] == null + ? undefined + : (json["items"] as Array).map(DtoJobFromJSON), + page: json["page"] == null ? undefined : json["page"], + page_size: json["page_size"] == null ? undefined : json["page_size"], + total: json["total"] == null ? undefined : json["total"], + }; +} + +export function DtoPageJobToJSON(json: any): DtoPageJob { + return DtoPageJobToJSONTyped(json, false); +} + +export function DtoPageJobToJSONTyped( + value?: DtoPageJob | null, + ignoreDiscriminator: boolean = false, +): any { + if (value == null) { + return value; + } + + return { + items: + value["items"] == null + ? undefined + : (value["items"] as Array).map(DtoJobToJSON), + page: value["page"], + page_size: value["page_size"], + total: value["total"], + }; +} diff --git a/sdk/ts/src/models/DtoQueueInfo.ts b/sdk/ts/src/models/DtoQueueInfo.ts new file mode 100644 index 0000000..5329eaf --- /dev/null +++ b/sdk/ts/src/models/DtoQueueInfo.ts @@ -0,0 +1,100 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * AutoGlue API + * API for managing K3s clusters across cloud providers + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from "../runtime"; +/** + * + * @export + * @interface DtoQueueInfo + */ +export interface DtoQueueInfo { + /** + * example: 5 + * @type {number} + * @memberof DtoQueueInfo + */ + failed?: number; + /** + * example: default + * @type {string} + * @memberof DtoQueueInfo + */ + name?: string; + /** + * example: 42 + * @type {number} + * @memberof DtoQueueInfo + */ + pending?: number; + /** + * example: 3 + * @type {number} + * @memberof DtoQueueInfo + */ + running?: number; + /** + * example: 7 + * @type {number} + * @memberof DtoQueueInfo + */ + scheduled?: number; +} + +/** + * Check if a given object implements the DtoQueueInfo interface. + */ +export function instanceOfDtoQueueInfo(value: object): value is DtoQueueInfo { + return true; +} + +export function DtoQueueInfoFromJSON(json: any): DtoQueueInfo { + return DtoQueueInfoFromJSONTyped(json, false); +} + +export function DtoQueueInfoFromJSONTyped( + json: any, + ignoreDiscriminator: boolean, +): DtoQueueInfo { + if (json == null) { + return json; + } + return { + failed: json["failed"] == null ? undefined : json["failed"], + name: json["name"] == null ? undefined : json["name"], + pending: json["pending"] == null ? undefined : json["pending"], + running: json["running"] == null ? undefined : json["running"], + scheduled: json["scheduled"] == null ? undefined : json["scheduled"], + }; +} + +export function DtoQueueInfoToJSON(json: any): DtoQueueInfo { + return DtoQueueInfoToJSONTyped(json, false); +} + +export function DtoQueueInfoToJSONTyped( + value?: DtoQueueInfo | null, + ignoreDiscriminator: boolean = false, +): any { + if (value == null) { + return value; + } + + return { + failed: value["failed"], + name: value["name"], + pending: value["pending"], + running: value["running"], + scheduled: value["scheduled"], + }; +} diff --git a/sdk/ts/src/models/DtoUpdateAnnotationRequest.ts b/sdk/ts/src/models/DtoUpdateAnnotationRequest.ts new file mode 100644 index 0000000..5205206 --- /dev/null +++ b/sdk/ts/src/models/DtoUpdateAnnotationRequest.ts @@ -0,0 +1,82 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * AutoGlue API + * API for managing K3s clusters across cloud providers + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from "../runtime"; +/** + * + * @export + * @interface DtoUpdateAnnotationRequest + */ +export interface DtoUpdateAnnotationRequest { + /** + * + * @type {string} + * @memberof DtoUpdateAnnotationRequest + */ + key?: string; + /** + * + * @type {string} + * @memberof DtoUpdateAnnotationRequest + */ + value?: string; +} + +/** + * Check if a given object implements the DtoUpdateAnnotationRequest interface. + */ +export function instanceOfDtoUpdateAnnotationRequest( + value: object, +): value is DtoUpdateAnnotationRequest { + return true; +} + +export function DtoUpdateAnnotationRequestFromJSON( + json: any, +): DtoUpdateAnnotationRequest { + return DtoUpdateAnnotationRequestFromJSONTyped(json, false); +} + +export function DtoUpdateAnnotationRequestFromJSONTyped( + json: any, + ignoreDiscriminator: boolean, +): DtoUpdateAnnotationRequest { + if (json == null) { + return json; + } + return { + key: json["key"] == null ? undefined : json["key"], + value: json["value"] == null ? undefined : json["value"], + }; +} + +export function DtoUpdateAnnotationRequestToJSON( + json: any, +): DtoUpdateAnnotationRequest { + return DtoUpdateAnnotationRequestToJSONTyped(json, false); +} + +export function DtoUpdateAnnotationRequestToJSONTyped( + value?: DtoUpdateAnnotationRequest | null, + ignoreDiscriminator: boolean = false, +): any { + if (value == null) { + return value; + } + + return { + key: value["key"], + value: value["value"], + }; +} diff --git a/sdk/ts/src/models/HandlersMeResponse.ts b/sdk/ts/src/models/HandlersMeResponse.ts index c97cb08..abbcf94 100644 --- a/sdk/ts/src/models/HandlersMeResponse.ts +++ b/sdk/ts/src/models/HandlersMeResponse.ts @@ -64,6 +64,12 @@ export interface HandlersMeResponse { * @memberof HandlersMeResponse */ id?: string; + /** + * + * @type {boolean} + * @memberof HandlersMeResponse + */ + is_admin?: boolean; /** * * @type {boolean} @@ -121,6 +127,7 @@ export function HandlersMeResponseFromJSONTyped( ? undefined : (json["emails"] as Array).map(ModelsUserEmailFromJSON), id: json["id"] == null ? undefined : json["id"], + is_admin: json["is_admin"] == null ? undefined : json["is_admin"], is_disabled: json["is_disabled"] == null ? undefined : json["is_disabled"], organizations: json["organizations"] == null @@ -157,6 +164,7 @@ export function HandlersMeResponseToJSONTyped( ? undefined : (value["emails"] as Array).map(ModelsUserEmailToJSON), id: value["id"], + is_admin: value["is_admin"], is_disabled: value["is_disabled"], organizations: value["organizations"] == null diff --git a/sdk/ts/src/models/ModelsUser.ts b/sdk/ts/src/models/ModelsUser.ts index 2eebc65..7276d77 100644 --- a/sdk/ts/src/models/ModelsUser.ts +++ b/sdk/ts/src/models/ModelsUser.ts @@ -43,6 +43,12 @@ export interface ModelsUser { * @memberof ModelsUser */ id?: string; + /** + * + * @type {boolean} + * @memberof ModelsUser + */ + is_admin?: boolean; /** * * @type {boolean} @@ -88,6 +94,7 @@ export function ModelsUserFromJSONTyped( display_name: json["display_name"] == null ? undefined : json["display_name"], id: json["id"] == null ? undefined : json["id"], + is_admin: json["is_admin"] == null ? undefined : json["is_admin"], is_disabled: json["is_disabled"] == null ? undefined : json["is_disabled"], primary_email: json["primary_email"] == null ? undefined : json["primary_email"], @@ -116,6 +123,7 @@ export function ModelsUserToJSONTyped( : value["created_at"].toISOString(), display_name: value["display_name"], id: value["id"], + is_admin: value["is_admin"], is_disabled: value["is_disabled"], primary_email: value["primary_email"], updated_at: diff --git a/sdk/ts/src/models/index.ts b/sdk/ts/src/models/index.ts index 5fc70df..1d4ba42 100644 --- a/sdk/ts/src/models/index.ts +++ b/sdk/ts/src/models/index.ts @@ -2,20 +2,26 @@ /* eslint-disable */ export * from "./DtoAnnotationResponse"; export * from "./DtoAuthStartResponse"; +export * from "./DtoCreateAnnotationRequest"; export * from "./DtoCreateLabelRequest"; export * from "./DtoCreateSSHRequest"; export * from "./DtoCreateServerRequest"; export * from "./DtoCreateTaintRequest"; export * from "./DtoJWK"; export * from "./DtoJWKS"; +export * from "./DtoJob"; +export * from "./DtoJobStatus"; export * from "./DtoLabelResponse"; export * from "./DtoLogoutRequest"; +export * from "./DtoPageJob"; +export * from "./DtoQueueInfo"; export * from "./DtoRefreshRequest"; export * from "./DtoServerResponse"; export * from "./DtoSshResponse"; export * from "./DtoSshRevealResponse"; export * from "./DtoTaintResponse"; export * from "./DtoTokenPair"; +export * from "./DtoUpdateAnnotationRequest"; export * from "./DtoUpdateLabelRequest"; export * from "./DtoUpdateServerRequest"; export * from "./DtoUpdateTaintRequest"; diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 383be5e..82feed7 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -3,6 +3,7 @@ import { Route, Routes } from "react-router-dom" import { ProtectedRoute } from "@/components/protected-route.tsx" import { Login } from "@/pages/auth/login.tsx" +import { JobsPage } from "@/pages/jobs/jobs-page.tsx" import { LabelsPage } from "@/pages/labels/labels-page.tsx" import { MePage } from "@/pages/me/me-page.tsx" import { OrgApiKeys } from "@/pages/org/api-keys.tsx" @@ -28,6 +29,8 @@ export default function App() { } /> } /> } /> + + } /> } /> diff --git a/ui/src/api/archer_admin.ts b/ui/src/api/archer_admin.ts new file mode 100644 index 0000000..e34b95c --- /dev/null +++ b/ui/src/api/archer_admin.ts @@ -0,0 +1,40 @@ +import { withRefresh } from "@/api/with-refresh.ts" +import { makeArcherAdminApi } from "@/sdkClient.ts" + +const archerAdmin = makeArcherAdminApi() + +type ListParams = { + status?: "queued" | "running" | "succeeded" | "failed" | "canceled" | "retrying" | "scheduled" + queue?: string + q?: string + page?: number + pageSize?: number +} + +export const archerAdminApi = { + listJobs: (params: ListParams = {}) => { + return withRefresh(async () => { + return await archerAdmin.adminListArcherJobs(params) + }) + }, + enqueue: (body: { queue: string; type: string; payload?: unknown; run_at?: string }) => { + return withRefresh(async () => { + return await archerAdmin.adminEnqueueArcherJob({ body }) + }) + }, + retryJob: (id: string) => { + return withRefresh(async () => { + return await archerAdmin.adminRetryArcherJob({ id }) + }) + }, + cancelJob: (id: string) => { + return withRefresh(async () => { + return await archerAdmin.adminCancelArcherJob({ id }) + }) + }, + listQueues: () => { + return withRefresh(async () => { + return await archerAdmin.adminListArcherQueues() + }) + }, +} diff --git a/ui/src/auth/logout.ts b/ui/src/auth/logout.ts new file mode 100644 index 0000000..94171e2 --- /dev/null +++ b/ui/src/auth/logout.ts @@ -0,0 +1,21 @@ +import { authStore } from "@/auth/store.ts" +import type { DtoLogoutRequest } from "@/sdk" +import { makeAuthApi } from "@/sdkClient.ts" + +export async function logoutEverywhere(): Promise { + const tokens = authStore.get() + + if (!tokens?.refresh_token) { + authStore.logout() + return + } + + try { + const body: DtoLogoutRequest = { refresh_token: tokens.refresh_token } as DtoLogoutRequest + await makeAuthApi().logout({ body }) + } catch (err) { + console.warn("Logout API failed; clearing local state anyway", err) + } finally { + authStore.logout() + } +} diff --git a/ui/src/components/protected-route.tsx b/ui/src/components/protected-route.tsx index c61b0a5..6543395 100644 --- a/ui/src/components/protected-route.tsx +++ b/ui/src/components/protected-route.tsx @@ -1,6 +1,7 @@ -import { useAuth } from "@/auth/use-auth.ts" import { Navigate, Outlet, useLocation } from "react-router-dom" +import { useAuth } from "@/hooks/use-auth.ts" + export const ProtectedRoute = () => { const { authed } = useAuth() const loc = useLocation() diff --git a/ui/src/hooks/use-auth-actions.ts b/ui/src/hooks/use-auth-actions.ts new file mode 100644 index 0000000..d1674fe --- /dev/null +++ b/ui/src/hooks/use-auth-actions.ts @@ -0,0 +1,10 @@ +import { useCallback } from "react" +import { logoutEverywhere } from "@/auth/logout.ts" + +export function useAuthActions() { + const logout = useCallback(() => { + return logoutEverywhere() + }, []) + + return { logout } +} diff --git a/ui/src/auth/use-auth.ts b/ui/src/hooks/use-auth.ts similarity index 100% rename from ui/src/auth/use-auth.ts rename to ui/src/hooks/use-auth.ts diff --git a/ui/src/layouts/app-shell.tsx b/ui/src/layouts/app-shell.tsx index 2d8c8c3..595cfa7 100644 --- a/ui/src/layouts/app-shell.tsx +++ b/ui/src/layouts/app-shell.tsx @@ -2,12 +2,13 @@ import { useEffect, useState } from "react" import { meApi } from "@/api/me.ts" import { orgStore } from "@/auth/org.ts" import { authStore } from "@/auth/store.ts" -import { mainNav, orgNav, userNav } from "@/layouts/nav-config.ts" +import { adminNav, mainNav, orgNav, userNav } from "@/layouts/nav-config.ts" import { OrgSwitcher } from "@/layouts/org-switcher.tsx" import { Topbar } from "@/layouts/topbar.tsx" import { NavLink, Outlet } from "react-router-dom" import { cn } from "@/lib/utils.ts" +import { useAuthActions } from "@/hooks/use-auth-actions.ts" import { Button } from "@/components/ui/button.tsx" import { Sidebar, @@ -31,6 +32,7 @@ type Org = { export const AppShell = () => { const [orgs, setOrgs] = useState([]) + const { logout } = useAuthActions() useEffect(() => { let alive = true @@ -135,11 +137,34 @@ export const AppShell = () => { + + + Admin + + + {adminNav.map((n) => ( + + + + cn("flex items-center gap-2", isActive && "text-primary") + } + > + + {n.label} + + + + ))} + + +
-
diff --git a/ui/src/layouts/nav-config.ts b/ui/src/layouts/nav-config.ts index fba0811..05af218 100644 --- a/ui/src/layouts/nav-config.ts +++ b/ui/src/layouts/nav-config.ts @@ -28,7 +28,6 @@ export const mainNav: NavItem[] = [ { to: "/taints", label: "Taints", icon: SprayCanIcon }, { to: "/servers", label: "Servers", icon: ServerIcon }, { to: "/ssh", label: "SSH Keys", icon: FileKey2Icon }, - { to: "/jobs", label: "Jobs", icon: GrUserWorker }, ] export const orgNav: NavItem[] = [ @@ -38,3 +37,8 @@ export const orgNav: NavItem[] = [ ] export const userNav: NavItem[] = [{ to: "/me", label: "Profile", icon: User2 }] + +export const adminNav: NavItem[] = [ + { to: "/admin/users", label: "Users Admin", icon: Users }, + { to: "/admin/jobs", label: "Jobs Admin", icon: GrUserWorker }, +] diff --git a/ui/src/pages/jobs/jobs-page.tsx b/ui/src/pages/jobs/jobs-page.tsx new file mode 100644 index 0000000..31020a6 --- /dev/null +++ b/ui/src/pages/jobs/jobs-page.tsx @@ -0,0 +1,540 @@ +import { useEffect, useState, type FC } from "react" +import { archerAdminApi } from "@/api/archer_admin" +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" +import { Loader2, Plus, RefreshCw, Search, X } from "lucide-react" + +import { cn } from "@/lib/utils" +import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" +import { Textarea } from "@/components/ui/textarea" + +// Types (align with generated client camelCase) +type JobStatus = + | "queued" + | "running" + | "succeeded" + | "failed" + | "canceled" + | "retrying" + | "scheduled" +type DtoJob = { + id: string + type: string + queue: string + status: JobStatus + attempts: number + maxAttempts?: number + createdAt: string + updatedAt?: string + lastError?: string | null + runAt?: string | null + payload?: unknown +} +type DtoPageJob = { + items: DtoJob[] + total: number + page: number + pageSize: number +} +type QueueInfo = { + name: string + pending: number + running: number + failed: number + scheduled: number +} + +const STATUS: JobStatus[] = [ + "queued", + "running", + "succeeded", + "failed", + "canceled", + "retrying", + "scheduled", +] + +const statusClass: Record = { + queued: "bg-amber-100 text-amber-800", + running: "bg-sky-100 text-sky-800", + succeeded: "bg-emerald-100 text-emerald-800", + failed: "bg-red-100 text-red-800", + canceled: "bg-zinc-200 text-zinc-700", + retrying: "bg-orange-100 text-orange-800", + scheduled: "bg-violet-100 text-violet-800", +} + +function fmt(dt?: string | null) { + if (!dt) return "—" + const d = new Date(dt) + return new Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "short" }).format(d) +} + +// Small debounce hook for search input +function useDebounced(value: T, ms = 300) { + const [v, setV] = useState(value) + useEffect(() => { + const t = setTimeout(() => setV(value), ms) + return () => clearTimeout(t) + }, [value, ms]) + return v +} + +export const JobsPage: FC = () => { + const qc = useQueryClient() + + // Filters + const [status, setStatus] = useState("") + const [queue, setQueue] = useState("") + const [q, setQ] = useState("") + const debouncedQ = useDebounced(q, 300) + const [page, setPage] = useState(1) + const [pageSize, setPageSize] = useState(25) + + const key = ["archer", "jobs", { status, queue, q: debouncedQ, page, pageSize }] + + // Jobs query + const jobsQ = useQuery({ + queryKey: key, + queryFn: () => + archerAdminApi.listJobs({ + status: status || undefined, + queue: queue || undefined, + q: debouncedQ || undefined, + page, + pageSize, + }) as Promise, + keepPreviousData: true, + staleTime: 10_000, + }) + + // Queues summary (optional header) + const queuesQ = useQuery({ + queryKey: ["archer", "queues"], + queryFn: () => archerAdminApi.listQueues() as Promise, + staleTime: 30_000, + }) + + // Mutations + const enqueueM = useMutation({ + mutationFn: (body: { queue: string; type: string; payload?: unknown; run_at?: string }) => + archerAdminApi.enqueue(body), + onSuccess: () => qc.invalidateQueries({ queryKey: ["archer", "jobs"] }), + }) + const retryM = useMutation({ + mutationFn: (id: string) => archerAdminApi.retryJob(id), + onSuccess: () => qc.invalidateQueries({ queryKey: ["archer", "jobs"] }), + }) + const cancelM = useMutation({ + mutationFn: (id: string) => archerAdminApi.cancelJob(id), + onSuccess: () => qc.invalidateQueries({ queryKey: ["archer", "jobs"] }), + }) + + const busy = jobsQ.isFetching + + const data = jobsQ.data + const totalPages = data ? Math.max(1, Math.ceil(data.total / data.pageSize)) : 1 + + return ( +
+
+
+

Archer Jobs

+

+ Inspect, enqueue, retry and cancel background jobs. +

+
+
+ enqueueM.mutateAsync(payload)} + submitting={enqueueM.isPending} + /> + +
+
+ + {/* Queue metrics (optional) */} +
+ {queuesQ.data?.map((q) => ( + + + {q.name} + + + + + + + + + ))} +
+ + {/* Filters */} + + + Filters + + +
+ { + setQ(e.target.value) + setPage(1) + }} + onKeyDown={(e) => + e.key === "Enter" && qc.invalidateQueries({ queryKey: ["archer", "jobs"] }) + } + /> + {q && ( + + )} + +
+ + { + setQueue(e.target.value) + setPage(1) + }} + /> +
+ + +
+
+
+ + {/* Table */} + + + + + + ID + Queue + Status + Attempts + Run At + Updated + Actions + + + + {jobsQ.isLoading && ( + + + Loading… + + + )} + {jobsQ.isError && ( + + + Failed to load jobs + + + )} + {!jobsQ.isLoading && data && data.items.length === 0 && ( + + + No jobs match your filters. + + + )} + {data?.items.map((j) => ( + + + {j.id} + + + {j.queue} + + + + {j.status} + + + + {j.maxAttempts ? `${j.attempts}/${j.maxAttempts}` : j.attempts} + + {fmt(j.runAt)} + {fmt(j.updatedAt ?? j.createdAt)} + +
+ {(j.status === "failed" || j.status === "canceled") && ( + + )} + {(j.status === "queued" || + j.status === "running" || + j.status === "scheduled") && ( + + )} + +
+
+
+ ))} +
+
+ + {/* Pagination */} +
+
+ Page {page} of {totalPages} • {data?.total ?? 0} total +
+
+ + +
+
+
+
+
+ ) +} + +function Metric({ label, value }: { label: string; value: number }) { + return ( +
+
{label}
+
{value}
+
+ ) +} + +function DetailsButton({ job }: { job: DtoJob }) { + return ( + + + + + + + Job {job.id} + +
+ {job.lastError && ( + + + Last error + + +
{job.lastError}
+
+
+ )} + + + Payload + + +
+                {JSON.stringify(job.payload, null, 2)}
+              
+
+
+
+ + + + + +
+
+ ) +} + +function EnqueueDialog({ + onSubmit, + submitting, +}: { + onSubmit: (body: { + queue: string + type: string + payload?: unknown + run_at?: string + }) => Promise + submitting?: boolean +}) { + const [open, setOpen] = useState(false) + const [queue, setQueue] = useState("") + const [type, setType] = useState("") + const [payload, setPayload] = useState("{}") + const [runAt, setRunAt] = useState("") + + const canSubmit = queue && type && !submitting + + async function handleSubmit() { + const parsed = payload ? JSON.parse(payload) : undefined + await onSubmit({ queue, type, payload: parsed, run_at: runAt || undefined }) + setOpen(false) + setQueue("") + setType("") + setPayload("{}") + setRunAt("") + } + + return ( + + + + + + + Enqueue Job + +
+
+ + setQueue(e.target.value)} + placeholder="e.g. bootstrap_bastion" + /> +
+
+ + setType(e.target.value)} + placeholder="e.g. bootstrap_bastion" + /> +
+
+ +