HTTP API
The UI talks to the server over a JSON API under /api/v1/ and WebSockets under /ws/. You can call the same API from scripts and tools. The MCP server is a client of it.
The API follows the UI and may change between minor versions; see API stability.
Authentication
Section titled “Authentication”Requests are authenticated the same way as the browser:
| Auth mode | Send |
|---|---|
local |
Nothing. Every request is the local user |
oidc |
Authorization: Bearer <token>: a JWT from your identity provider whose audience is oidc_audience (the client ID by default) |
token |
Authorization: Bearer <token>: a Kubernetes token, which goes on to the API server |
impersonation |
Go through your auth proxy, which adds X-Forwarded-User and X-Forwarded-Groups |
Requests that change something (POST, PUT, PATCH, DELETE) must also carry Authorization, X-Requested-With, X-CSRF-Token or Content-Type: application/json; otherwise they are rejected as a possible cross-site request. A browser with a sign-in session (oidc and token modes) must send the session’s CSRF token, from GET /auth/session, in X-CSRF-Token.
Without a bearer token or a session, oidc and token modes answer 401 with the error sign_in_required, or cookie_conflict when the browser sent more than one session cookie (GET /auth/session then has cookieConflict: true).
Every Kubernetes call runs as the authenticated user, so the API returns the same 403 you would get from kubectl.
Other request headers KubeGlass reads:
| Header | Does |
|---|---|
X-Session-ID |
The browser session, and with it the chosen cluster. Without it, the kubeglass-session-id cookie is used, and a new session starts when there is neither, or when the session belongs to another user |
X-Impersonate-User, X-Impersonate-Group |
Act as another user and groups, like kubectl --as and --as-group, after KubeGlass checks that you may impersonate them. Groups may repeat or be comma-separated. WebSockets take as and asGroup query parameters instead |
X-KubeGlass-Read-Only: 1 |
Refuse the request with 403 read_only if it would change the cluster. The UI sends it for a cluster you marked read-only |
X-KubeGlass-Cluster |
Act on this context instead of the session’s, without switching the session, as you: Act As covers the session’s context only. A context that isn’t in the kubeconfig is 404 context_not_found. Lists that show several clusters send it for each one |
X-KubeGlass-Context |
The cluster the client shows. When the session is on another one, the request is refused with 409 context_mismatch, and context in the body names the session’s cluster; switching the session passes. The UI sends it with every request, except while a switch moves the session |
A header carries a name as it is when the name is printable ASCII without spaces at its ends. Any other name, such as a context called 本番 or café-prod, goes as percent-encoded UTF-8 after UTF-8'', as RFC 8187 writes it: X-KubeGlass-Context: UTF-8''%E6%9C%AC%E7%95%AA. Browsers send only Latin-1 in a header. In X-Impersonate-Group each group is encoded, so a comma in one is %2C, and asGroup on a WebSocket takes a group with a comma in it the same way. A value that doesn’t decode to UTF-8 without control characters is refused with 400. A context’s name may be any UTF-8 without control characters, up to 253 characters.
Choosing the cluster
Section titled “Choosing the cluster”Requests act on the session’s current context. Switch it with PUT /api/v1/contexts/{name}/switch, or name another context for one request with X-KubeGlass-Cluster.
Responses and errors
Section titled “Responses and errors”Most successful responses put the result in data, with meta for paged lists. A few return the result as the whole body: GET /api/v1/problems, GET /api/v1/contexts/problems, GET /api/v1/graph, GET /api/v1/vulnerabilities, GET /api/v1/policy/violations, GET /api/v1/certificates and GET /api/v1/audit/events. Errors have a status code and a body like:
{ "error": "not_found", "message": "pods \"web-1\" not found", "requestId": "4f1c…"}error is a stable code; see Error codes. Include requestId when you report a problem: it appears in the server log next to the failure.
Status summaries
Section titled “Status summaries”Lists from /api/v1/objects, single-object GETs and /ws/watch events come with a summary of each object’s status, so a client doesn’t need rules for every kind:
| Field | Holds |
|---|---|
tone |
ok, warn, error, progress or neutral (kinds with no health of their own, such as ConfigMaps) |
state |
For pods, the STATUS column of kubectl get pods. For other kinds a code such as Available, Progressing, ShortOfReplicas (a Deployment short of replicas whose pods don’t say since when), Degraded, ScaledDown, Complete, Failed, Running, Suspended, Active, Bound, Pending, Ready, NotReady, Cordoned or Terminating |
ready |
ready/total: a pod’s containers, a workload’s replicas, a job’s completions |
restarts |
A pod’s container restarts |
problem |
Empty when the object is fine. Pod codes such as CrashLoop, ImagePull, ConfigError (a ConfigMap, Secret or key the container refers to is missing), RuntimeError (the container runtime couldn’t create or start the container), OOMKilled, Unschedulable; for other kinds RolloutStuck, Unavailable, ReplicaFailure, JobFailed, CronJobFailing, NodeNotReady, NodePressure, PVCPending, PVCLost, PVFailed, HPAUnable, PDBBlocking, NamespaceStuck, CertNotReady, CertExpiring, ArgoDegraded, ArgoOutOfSync, ConditionFalse for custom resources whose Ready, Available, Healthy or Synced condition is False, and in problems only AlertFiring for a firing Alertmanager alert about the object (state is the alert’s name, message its summary) |
container |
The container a pod’s problem is about |
message |
The cluster’s own words: a condition, termination or scheduler message |
since |
When the state or problem began, if known (RFC 3339) |
GET /api/v1/objects/{group}/{version}/{resource} lists any kind, custom resources included (_core stands for the core group). It takes namespace, labelSelector and fieldSelector, returns every object (it follows the API server’s continue tokens) and answers { "data": [...], "summaries": { "<uid>": {...} } }. With table=1 it also returns columns and cells (by UID) from the API server’s Table form, which are the columns kubectl get prints, a custom resource’s printer columns included. Objects come without managedFields, and Secrets keep their keys with empty values.
Search
Section titled “Search”POST /api/v1/search with { "query": "web prod", "namespace": "", "maxResults": 50 } searches, as you, every kind KubeGlass keeps in its cache (all the built-in kinds the UI lists, except events). It looks at names, namespaces, kinds, labels (each as its key, its value and key=value), container images, each object’s state and problem, and addresses: the IPs of pods, Services and nodes, a Service’s external name and load balancer addresses, an Ingress’s hosts and load balancer addresses, and the addresses an EndpointSlice lists. A pod also matches its node’s name and IP. So crash or pending finds objects in that state, 10.42.0.17 from a log line finds what has that address, a node’s name or IP finds the node first and then the pods on it, and app=web finds the objects with that label. Every word must match. A query that holds IP addresses, such as a whole log line (dial tcp 10.42.0.17:8080: connection refused), searches for those addresses, without their ports, and finds what has any of them; an address matches whole, so 10.42.0.1 doesn’t find 10.42.0.17. Results come best first, 50 by default and at most 100, each { "type": "resource", "score", "resource": { group, version, resource, kind, namespace, name, uid, labels, summary, url } }. With a namespace, cluster-scoped kinds are still searched. A kind you can’t list in every namespace is searched in each of namespaces instead, the first 25 of them (the palette sends the allowed namespaces from your cluster settings, or the namespace in view), one page of 500 objects each; without them, in your kubeconfig context’s namespace, if it names one. A list the API server refused (403) isn’t asked again for a minute; one it answered 401, for credentials a credential plugin may renew, is. meta.namespaces names those it could read such kinds in, and meta.unsearched the kinds you may list in none of the places searched.
namespaces takes at most 100 names, as many as the allowed namespaces setting holds, on every endpoint that reads it: POST /api/v1/search, GET /api/v1/images, GET /api/v1/rollouts, GET /api/v1/rightsizing, GET /api/v1/certificates and GET /api/v1/timeline. More answer 400 invalid_namespace.
Events
Section titled “Events”GET /api/v1/events (or /api/v1/namespaces/{namespace}/events) lists events, newest first, with repeats merged; events of the same second come in the order they were made, the last first. involvedKind and involvedName pick one object’s events, and involvedUID those of the object with that UID only, as kubectl describe lists them: an object deleted and made again under its name, as StatefulSet pods are, leaves events that stay for an hour. Events with no UID are kept, and so are a node’s kubelet events, which carry the node’s name as the UID. With includeOwned=true and a namespace, the events of what that object owns come too, at any depth: a Deployment’s ReplicaSets and their Pods, a CronJob’s Jobs and Pods, a StatefulSet’s Pods. A workload’s own events rarely say why its pods fail; its pods’ events do (image pulls, scheduling, back-offs). type (Normal or Warning), reason and severity filter further.
Alertmanager and Prometheus
Section titled “Alertmanager and Prometheus”KubeGlass uses one Alertmanager: the URL in Settings, or the one it finds in its current context, and it answers only for that cluster. A cluster can have a Prometheus of its own (PUT /api/v1/settings/clusters/{cluster} with {"prometheus_url": "..."}, admins only); otherwise the Prometheus is the one in Settings or found in the current context, for that cluster only. For a session on another cluster, GET /api/v1/metrics/alerts returns no alerts, GET /api/v1/alertmanager/status returns available: false with otherCluster naming the cluster KubeGlass uses, silences answer 404 dependency_unavailable, and POST /api/v1/metrics/query answers 503 prometheus_other_cluster unless that cluster has a Prometheus of its own.
Silences are read as KubeGlass, by whoever may list pods in every namespace, and created and expired as the user: a found Alertmanager through the service proxy with the user’s identity, so they need create (POST) or delete (DELETE) on services/proxy for its Service, and a refusal answers 403 naming it; an Alertmanager URL in Settings takes them from KubeGlass admins only. createdBy is always the signed-in user, followed by as and the Act As identity when the request acts as it, on the session’s cluster; a value in the request is replaced.
Problems
Section titled “Problems”GET /api/v1/problems?namespace= lists what needs attention in the cluster, one row per object: every object whose summary has tone error or warn, errors first, then the newest. Pods are rolled up to the controller at the top of their owners (a ReplicaSet’s Deployment, a Job’s CronJob), so three crash-looping pods of one Deployment are one row with count 3, owner set and from naming the pod the summary is from. On a chain of owners the finding that says most wins: a workload’s own Unavailable is left out when its pods say why, and a failed Job’s pods are left out because the Job’s failure says more. It reads pods, workloads, jobs, CronJobs, nodes, PVCs, autoscalers, disruption budgets, namespaces and Services, plus cert-manager Certificates and Argo CD Applications when those are installed.
Each row can carry:
| Field | Holds |
|---|---|
also |
The object’s other problems, each { summary, count }, and Services its pods leave without ready endpoints, as { summary: { problem: "NoReadyEndpoints" }, object: { kind: "Service", name } } |
alerts |
Firing Alertmanager alerts of severity critical or warning whose labels (pod, deployment, statefulset, daemonset, job_name, cronjob, persistentvolumeclaim, horizontalpodautoscaler, service or node) name the object or one it owns, as { name, tone, severity, summary, since } |
change |
The last change (see Timeline) to the object, to a ConfigMap or Secret its pods read (not the cluster’s CA bundle), or to the Helm release it belongs to, in the day before the problem began, if you may list that kind there |
An object with only an alert gets a row whose problem is AlertFiring. Alerts are included for the cluster KubeGlass polls Alertmanager in, if you may list pods there (in the namespace asked for, or everywhere); those that name no object are listed in alerts as { name, tone, severity, namespace, summary, since, labels }. unavailable names the sources you may not read, alerts included, and unanswered those whose list got no answer while the others did (a connection that broke off), so asking again may find their problems; alerts is there too until Alertmanager has answered KubeGlass once, in the first seconds after a start or while it can’t be reached. When no list got an answer, or the pods list didn’t, it answers 502 (api_unreachable, or credentials_failed when the kubeconfig’s credential plugin failed).
GET /api/v1/contexts/problems checks every kubeconfig context, as you, and gives for each: reachable, counts of errors and warnings over the rows and the alerts that name no object, as the Overview counts them (with nodes, ready and total, when you may list nodes), the first 20 rows, the first 5 of those alerts, and unavailable and unanswered for the kinds. Those two never name alerts: a cluster whose alerts you may not read, or whose Alertmanager hasn’t answered KubeGlass yet, just has none. GET /api/v1/problems without a namespace has the same nodes. Clusters are checked a few at a time; one that doesn’t answer /healthz within 3 seconds is unreachable and doesn’t hold up the rest. One that isn’t reachable has an error: the cluster didn't answer, the cluster refused the credentials (401), KubeGlass's credentials for the cluster may not act for you (403 on impersonating you), the cluster refused this user (any other 403), or why KubeGlass has no clients for it. With Act As, only the session’s cluster is checked as that identity, also when the request names another; the others as you. Results are reused for 15 seconds, per cluster and identity.
GET /api/v1/graph?namespace=&groupBy=&problemsOnly= returns the map the Map page draws: the objects a namespace’s applications are made of (the whole cluster without namespace), how they connect, and what is wrong along each chain. Everything is listed as you, so the map has only what you may list; unavailable names the resources you may not, unanswered those whose list got no answer while the others did, and Secrets you can’t list still appear where something refers to them, without a state. As with problems, a cluster whose API server doesn’t answer gets 502 api_unreachable.
nodes are Ingresses, Gateways, HTTPRoutes and GRPCRoutes, Services, Deployments, StatefulSets, DaemonSets, CronJobs, Jobs, pods (finished pods left out), PersistentVolumeClaims, and the ConfigMaps, Secrets and service accounts something refers to. A Deployment’s ReplicaSets are drawn as the Deployment. Each node has id (Kind/namespace/name), apiVersion, resource, kind, namespace, name, the summary the lists show, detail (an Ingress’s hosts, a Service’s type and ports, a claim’s size and class, a pod’s node, a CronJob’s schedule) and box, the ID of the group it is drawn in. problem is { summary, count } when something needs attention: the row GET /api/v1/problems has for the object (a Deployment gets its pods’ crash loop, with count of them), or else its own summary. Services also get NoReadyEndpoints when they select pods and none is ready, and NoMatchingPods (with the selector as message) when their selector matches no pod and no workload’s pod template. An object something refers to that doesn’t exist has missing set and the problem NotFound, unless the reference is optional.
edges are { from, to, type }, pointing the way traffic and ownership go:
| Type | From and to |
|---|---|
routes |
Ingress, HTTPRoute or GRPCRoute to a Service; Gateway to a route |
selects |
Service to the workloads (or bare pods) its selector matches |
owns |
Deployment, StatefulSet, DaemonSet or Job to its pods; CronJob to its Jobs |
mounts |
Workload or pod to the ConfigMaps, Secrets and claims it has as volumes |
uses |
Workload or pod to what its environment, image pull secrets and service account name; Ingress or Gateway to its TLS Secret |
groupBy is namespace (the default), node or app; groups lists the boxes as { id, kind, label, namespace, source }. With app, workloads are grouped as the Applications page groups them (Helm release, Argo CD application, app.kubernetes.io labels) and the IDs match its namespace/name@source keys; with node, pods go in their node’s box and other objects in the box everything they connect to shares. problemsOnly=true keeps the problem chains: every node with a problem, every node with a path to one, and what a node with a problem mounts or uses. The map holds at most 2,000 nodes, problem chains first; truncated is set when there were more, and total counts them.
Audit events
Section titled “Audit events”GET /api/v1/audit/events?q=&user=&resource=&action=&result=&context=&limit=&after=&before= returns the latest changes made through KubeGlass, newest last, as { "events", "total", "logStart" }, 100 by default and at most 500 (limit). The filters look through every event the server keeps (the latest 5,000), before the cut, and events holds the newest limit of those that match; total counts all that match, with after or before those on that side of the cursor, so total larger than the length of events means there are older ones. q is for a search box: every word must appear in the event’s user or the identity it acted as (UserID or ActAsUser), action, resource, name, namespace or cluster. user and resource match part of that one field (user the signed-in user’s only), and action and result take comma-separated values. context keeps the changes on those clusters (kubeconfig context names, comma-separated) and the changes to KubeGlass itself, which have no Context whichever cluster the session was on: its settings (PUT /api/v1/settings, POST /api/v1/settings/test-webhook), the clusters it connects to (the POST routes under /api/v1/connect/ and DELETE /api/v1/connect/clusters/{name}), cluster switches (PUT /api/v1/contexts/{name}/switch), the extensions file (PUT /api/v1/extensions/file), Helm repositories (POST /api/v1/helm/repos and /api/v1/helm/repos/update) and drift policies and scans (the POST and DELETE routes under /api/v1/drift/). A cluster’s own settings (PUT /api/v1/settings/clusters/{cluster}, PUT /api/v1/me/clusters/{cluster} and /api/v1/me/clusters/{cluster}/namespaces) have that cluster’s Context. These routes are matched by method and whole path, so a change to a cluster’s object that shares a name with one, such as a label on Rancher’s settings.management.cattle.io (PATCH /api/v1/settings/{name}/metadata), has the session’s cluster. Every filter given must match. after returns only events after that seq, for polling, and before only events before it: to page back, pass the seq of the oldest event you have.
Each event has its seq, which rises with each event the server records and starts again when it restarts, and its timestamp. logStart is when the log started, with the server: a client that keeps events tells a log that started again, and has grown past the seq it had, from the old one by it. It records who made the change (UserID and UserGroups) and, for a change made with Act As, the identity it was made as (ActAsUser and ActAsGroups), which the cluster authorized it for; events without Act As, changes to KubeGlass itself and to a cluster’s KubeGlass settings, which no cluster authorizes, and those recorded before these fields, have neither. Each also has the action (scale, restart, cordon, delete and so on), the object’s APIGroup, Resource, Namespace and Name when the route names them, the cluster (Context) and the result. Details holds the request path, the HTTP status and a SHA-256 hash of the body. The body itself is not stored. The result is success, failure or denied; a Helm operation that runs in the background has an event with accepted when it starts and another with its outcome when it ends, or unknown when KubeGlass stopped before it did.
Access
Section titled “Access”GET /api/v1/rbac/matrix/{subject} says what a subject may do, read from the cluster’s roles and bindings. {subject} is a user or group name, or a ServiceAccount as system:serviceaccount:<namespace>:<name>; kind=Group reads it as a group (User is the default). Each group= adds a group whose bindings count too, besides system:authenticated (and for a ServiceAccount system:serviceaccounts and system:serviceaccounts:<namespace>), which always count. With namespace, the answer is for that namespace alone, merging what is granted there and everywhere. It answers { subject: { kind, name, namespace }, groups, namespace, rules } with one rule per resource and place: { apiGroup, resource, resourceNames, namespace, verbs, grants }, where a rule’s namespace is empty for every namespace and each grant is { roleKind, role, bindingKind, binding, namespace }.
GET /api/v1/rbac/who-can-access?verb=&resource=&namespace= lists the subjects a binding gives that access, each { subject, subjectKind, namespace, roleName, roleKind, binding, bindingKind, bindingNamespace, limitedTo }, matching rules as the API server’s RBAC does. resource may name its API group and a subresource as kubectl does (deployments.apps, pods/log); without a group it is the group the cluster’s discovery gives, the core group first, as kubectl picks it, and group in the answer says which (absent when the cluster doesn’t serve the resource, and then a rule naming it counts in any group). limitedTo lists the objects a role’s resourceNames limit the access to, when it gives no more; RBAC can’t limit create or deletecollection of a resource by name, so such a rule counts for neither, and namedRulesIgnored says a role bound to someone had one. resource is read in any case. notServed says the cluster serves no resource by that name (in the group given, with one), and servedAs the resource it stands for when it is a short name or kind (deploy and Deployment for deployments.apps); the list then is only what the rules say. When KubeGlass couldn’t read the cluster’s discovery, it can’t tell whether the cluster serves a resource that isn’t built in: the answer then has discoveryUnavailable instead of notServed, with the subjects the rules give it to. Without namespace, RoleBindings in every namespace count.
Both read the Roles, ClusterRoles and bindings as you. They answer 403 with the API server’s reasons in detail when you may list neither RoleBindings nor ClusterRoleBindings. When you may list some of the four, they answer with what those say: refused lists the others as { kind, reason }, and unread has the grants to roles you may not read as { roleKind, role, bindingKind, binding, namespace } (the subject’s, for the matrix; any binding’s, for who can, whose subjects may have the access too). Who can puts them beside data. An invalid namespace is a 400. GET /api/v1/authz/rules?namespace= says what you may do in a namespace, from a SelfSubjectRulesReview, which the API server answers for any user: { namespace, rules, incomplete, evaluationError }, one rule per resource as { apiGroup, resource, resourceNames, verbs }. incomplete is the API server’s word that another authorizer may allow more, and evaluationError says what kept it from reading some of the rules. GET /api/v1/authz/identity returns { user, groups }, who the session’s cluster takes you for (a SelfSubjectReview). POST /api/v1/rbac/roles and POST /api/v1/rbac/bindings create a ClusterRole or ClusterRoleBinding when the body has clusterScoped: true.
Vulnerabilities
Section titled “Vulnerabilities”GET /api/v1/vulnerabilities?namespace=&severity=&fixable=&image=&q= reads the Trivy Operator’s VulnerabilityReports as you and answers { vulnerabilities, summary, matched, scanner }. vulnerabilities holds the findings, most severe first and then by score, at most 500: each with vulnerabilityID, severity, title, resource (the package), installedVersion, fixedVersion, score, primaryLink, image, namespace, workloadKind, workloadName and reportName. summary counts every finding that passed the filters: total, bySeverity, fixable, uniqueImages, uniqueCVEs and reportCount. severity takes one level (CRITICAL, HIGH, MEDIUM, LOW or UNKNOWN), fixable=true keeps findings with a fixed version, and image keeps images whose name contains it. q is a search: each of its words must appear in a finding’s CVE ID, title, package, installed version, image, namespace or workload. It looks through every finding before the list is cut, and summary doesn’t follow it; matched counts the findings that match it (with no q, every finding summary counts), so matched larger than the list’s length means the list was cut.
scanner says whether there were reports to read, since no findings is only an all-clear when there were:
scanner |
Means |
|---|---|
ok |
The reports were read |
notInstalled |
The cluster doesn’t serve VulnerabilityReports: the Trivy Operator isn’t installed |
forbidden |
You may not list the reports (in that namespace, or in every namespace without one) |
unavailable |
The API server didn’t answer the list |
Policies
Section titled “Policies”GET /api/v1/policy/violations?engine=&severity=&namespace=&namespaces= reads OPA Gatekeeper’s constraints and Kyverno’s PolicyReports and ClusterPolicyReports as you and answers { violations, summary, engines, skippedNamespaces, skippedClusterReports, skippedConstraints, unavailableConstraints, clusterReportsUnavailable, truncated }. violations holds each violation, most urgent first, with engine, policy, rule (Kyverno’s), severity (empty when the policy gives none), message, resourceKind, resourceName, resourceNamespace, action (deny, warn, audit or dryrun, empty when KubeGlass couldn’t read the policy) and category. summary counts them: total, bySeverity (none for those without a severity), byEngine, byAction and policyCount. engine takes gatekeeper or kyverno, and severity a severity in any case, or none. namespace picks one namespace and namespaces (comma-separated) several, such as a cluster’s allowed namespaces; violations of cluster-wide objects come with either. Without them, Kyverno’s PolicyReports are read across the cluster or, if you may not list them there, in each namespace you may list, or else in the kubeconfig context’s namespace.
engines says, for each engine asked about, whether its reports were read, since no violations is an all-clear only from an engine that was: ok, notInstalled, forbidden or unavailable, as scanner does for Vulnerabilities. An engine read in part is ok, and these say what was left out:
| Field | Means |
|---|---|
skippedConstraints |
The ConstraintTemplates whose constraints you may not list |
unavailableConstraints |
The ConstraintTemplates whose constraints the API server didn’t list |
skippedNamespaces |
The namespaces whose PolicyReports you may not list, when you may not list them across the cluster |
skippedClusterReports |
You may not list the ClusterPolicyReports, Kyverno’s reports on cluster-wide objects |
clusterReportsUnavailable |
The API server didn’t list the ClusterPolicyReports |
truncated names the Gatekeeper constraints whose audit lists fewer violations than it counts (--constraint-violations-limit, 20 by default), each { engine, policy, listed, total }. Without namespace or namespaces, summary counts the ones not listed too.
Certificates
Section titled “Certificates”GET /api/v1/certificates?namespace=&namespaces=&status= reads kubernetes.io/tls Secrets and cert-manager’s Certificates as you and answers { certificates, summary, skippedNamespaces, secretsRefused, certManager, certManagerSkippedNamespaces }. Each certificate has name, namespace, source (secret or cert-manager), dnsNames, commonName, issuer, notBefore, notAfter, daysRemaining (negative once it expired), status, serialNumber, isCA, keyAlgorithm and keySize, and one cert-manager manages has certManagerIssuerRef, certManagerReady, certificateName and secretName. status is valid, expiring-soon (within 30 days), expired, not-yet-valid or parse-error, or for a Certificate not issued yet issuing, issue-failed or pending, with the reason in statusReason. A Secret’s dates are those of its leaf certificate, and chainExpiresFirst ({ commonName, notAfter, expired }) names a certificate further up the chain in its tls.crt that expires before the leaf. status= keeps one status, and summary counts what it keeps: total, valid, expiringSoon, expired, parseErrors, notYetValid, issuing, issueFailed and pending. namespace and namespaces pick namespaces as for Policies; without them, Secrets and Certificates are each read across the cluster or in each namespace you may list them in, or, when you may not list namespaces, in your kubeconfig context’s namespace.
An empty list is an all-clear only when everything was read:
| Field | Means |
|---|---|
secretsRefused |
You may list Secrets in none of the namespaces asked about: the list is cert-manager’s Certificates only, with the dates from their status |
skippedNamespaces |
The namespaces whose Secrets you may not list. Where their Certificates were read, those are listed from their status, without the certificate’s own details |
certManager |
Whether cert-manager’s Certificates were read: ok, notInstalled, forbidden or unavailable |
certManagerSkippedNamespaces |
The namespaces whose Certificates you may not list. Where their Secrets were refused too, nothing of the namespace is listed |
It answers 403 only when both Secrets and Certificates were refused everywhere asked.
Files in a pod
Section titled “Files in a pod”The Files view’s routes run commands in a container through the exec API, as you, so they need create on pods/exec. Each takes container and path (an absolute path in the container):
| Route | Does |
|---|---|
GET /api/v1/namespaces/{namespace}/pods/{pod}/files |
Lists the folder at path: each entry’s name, path, type (file, directory or symlink), size, permissions, owner, group, modifiedAt and a symlink’s target: the first 2,000 by name, with meta.total saying how many the folder holds |
GET …/files/content |
A text file of up to 1 MiB as { content, size }; a larger file answers 413 and a binary one 415, to be downloaded instead |
GET …/files/download |
Streams the file (cat in the container). With archive=true, which a folder needs, it streams path as a tar archive made by the container’s tar |
POST …/files/upload |
Writes the request body into the folder path as the file name |
A folder listing that takes longer than 20 seconds in the container (one of very many entries on a busy node, say) answers 504 timeout, and so does a file preview that does (a pipe, a device file or a slow mount). A download of a pipe or a device waits the same way, so the message says to read it with kubectl exec and a command that stops.
An upload’s body is the file itself, with a Content-Length of at most 256 MiB (413 beyond it, 411 without one). name is one path segment, at most 255 bytes, without control characters. Without overwrite=true a file of that name answers 409 already_exists; a folder of that name always answers 409. The file arrives under a hidden temporary name and takes its name only once all of it is there, so an upload that stops leaves nothing behind. The answer is 201 with { path, size, sha256 }, and the audit log records the file, its size and its SHA-256.
Send the same request with check=true and no body first. KubeGlass then runs only the check the upload starts with and answers 204, or the error the upload would get: 422 for a container without a shell or without the tools an upload uses (tar or cat, and mv, wc and rm), 404 for a folder that doesn’t exist and 400 for one that isn’t a folder, 403 for a folder the container user may not write to or a read-only filesystem, and 409 for a file of that name without overwrite=true. A script learns that before it sends 256 MiB. A full upload runs the same check first and reads at most 1 MiB of a refused body.
Uploads and downloads have no API timeout but 15 minutes each, which for an upload starts when its check has passed; up to 6 run at once for one user and 32 in all (429 too_many_transfers beyond that, with Retry-After). Read-only mode refuses uploads.
Applying manifests
Section titled “Applying manifests”POST /api/v1/apply applies a manifest as you, like kubectl apply --server-side -f. The body is { yaml, namespace }: one or more objects as YAML or JSON, documents separated by --- lines, each an object or a List, and the namespace for objects of namespaced kinds that name none (default when left out). Each object goes through Server-Side Apply with field manager kubeglass; an object with only generateName is created. Namespaces go first, then CustomResourceDefinitions (KubeGlass waits until each is established), then the rest in the manifest’s order. An object can name any version its API group serves, such as autoscaling/v1 for a HorizontalPodAutoscaler, as with kubectl apply; a version the group doesn’t serve fails with the versions it does. dryRun=true has the API server check every object without saving, and force=true takes over fields another field manager owns, like --force-conflicts.
The answer is { dryRun, results, failed } with one result per object in the manifest’s order: document (and item within a List), the line it’s about, apiVersion, kind, name, namespace (namespaceDefaulted when it came from the body) and action: created, configured, unchanged, applied (it worked, but you may not read the object), skipped (a dry run can’t check an object in a namespace or of a kind the same manifest creates) or error, with the API server’s message and reason. conflict marks an object that force=true would apply. A dry run adds before and after for objects it would change, without managedFields and with Secret values REDACTED. When every object fails the status is 422 apply_failed, with the results in data. Objects of one kind in a row go to the API server eight at a time. An apply may run 55 seconds; the objects it has no time for come back as error with a message that they weren’t applied, so the answer always has every object’s result, and applying the manifest again applies them.
POST /api/v1/manifests/fetch with { url } downloads a manifest and returns { yaml } without applying it. The URL must be HTTPS, redirects included, and reach a public address; the file must be at most 2 MiB of YAML or JSON with at least one object.
Projects
Section titled “Projects”A project is the namespaces that carry the same kubeglass.io/project label; one that only has Headlamp’s headlamp.dev/project-id counts too. The namespace list has the labels, so there is no endpoint to list projects. POST /api/v1/projects/apply changes which namespaces a project has, as you: the body is { project, add, create, remove }, the namespaces to put in it, to create in it and to take out of it (they aren’t deleted). Adding sets kubeglass.io/project, and headlamp.dev/project-id too when the namespace has that label; removing takes away either label where it names this project. dryRun=true has the API server check each change without saving. The answer is { dryRun, project, results, failed } with one result per namespace: namespace, change (create, add or remove), action (create, label, unlabel, unchanged or error, with the API server’s message and reason), the namespace’s labels before and after, and fromProject when it was in another project. When every change fails the status is 422, with the results in data.
Your cluster settings
Section titled “Your cluster settings”GET /api/v1/me/clusters returns { storage, user, clusters }. With storage: "server" (every auth mode but local, with a data directory) the server keeps each user’s settings by kubeconfig context, keyed by the signed-in user name: displayName, defaultNamespace, production, readOnly, color and allowedNamespaces. PUT /api/v1/me/clusters/{cluster} replaces yours for one cluster, and an empty object removes them. With storage: "browser" the UI keeps them and the PUT answers 409. Read-only mode lets these through, as they change only your own view.
In local mode the answer also has namespaces: the namespaces the browser said you work in, by kubeconfig context, which the change recorder looks at first where KubeGlass’s credentials may not list a kind in every namespace (see Credentials limited to some namespaces). PUT /api/v1/me/clusters/{cluster}/namespaces with { namespaces } replaces them for one cluster, the most wanted first: at most 128 namespace names, and an empty list removes them. It answers with what KubeGlass kept, and a list it can’t take with 400. In the other modes namespaces is absent and the PUT answers 409 not_local, since the server reads each user’s own settings.
GET /api/v1/settings/clusters returns KubeGlass’s own per-cluster settings, { clusters, editable }, today each cluster’s prometheus_url; PUT /api/v1/settings/clusters/{cluster} sets them (admins only).
Undoing a change
Section titled “Undoing a change”GET /api/v1/changes?namespace=&resource=&name=&after=&automatic=&limit= lists the changes, newest first, as { changes, total, since, automaticSince, unrecorded, partlyRecorded, history }, 200 by default and at most 1,000: those the recorder saw since since, those read from the cluster’s own records, which carry a source (replicasets, controllerrevisions, helm or metadata) and can be older, and deletes and Helm uninstalls made through KubeGlass that the recorder doesn’t watch for, with source audit. Each change has an id, action (created, updated or deleted), the object (with its uid when known), the fields an update changed, the field manager and, for changes made through KubeGlass, the user (alice as bob for a change made with Act As). A workload’s or Helm release’s change has the revision it made and may have a cause; a Helm rollback has rollbackTo, the revision it went back to, and an object a Helm uninstall deleted has the release it was part of; an update read from managed fields has fieldsUnknown, and a revision dated by an estimate has timeEstimated. Automatic changes have automatic and are listed only with automatic=true; one that stands for several updates by its field manager has their count and the time of the last in until (see What is recorded). since is when the record of the other changes is complete from, and automaticSince, when it is later, the same for automatic changes. history says whether the cluster’s records were read yet (state is reading or done) and which couldn’t be (unread, such as replicasets or helmreleases), in the namespace asked for or, without namespace=, anywhere; it is absent when nothing reads them. unrecorded names the kinds KubeGlass records no changes to, the same way. Where its credentials allow some namespaces only, partlyRecorded (and history.partlyRead for the records) lists each such kind with the namespaces it is recorded in, the namespaces it leaves out past the 25 it records (leftOut, the first 25 or the one asked for, and leftOutCount), naming only namespaces you may list the kind in; with namespace=, only that one. A Helm release’s changes are told as changes to kind HelmRelease (group helm.sh, resource helmreleases) and are listed for whoever may list Secrets in its namespace. revertible is set when KubeGlass can undo it; otherwise noRevert says why (secret, large, expired, unknown, superseded, helm, deleted or folded). reverted is set once it was undone.
POST /api/v1/namespaces/{namespace}/{resource}/{name}/revert?change=<id> undoes one, as you: for an update it applies a merge patch back to the earlier values, and for a deleted object it creates the object again. Add group= for a kind outside the core group (apps for Deployments) and dryRun=true to have the API server check it without saving. The answer is { before, after, dryRun }: the object now (null for a deleted one) and after the revert. It fails with 409 already_reverted, with 409 changed_since and the paths that changed again since, with 409 replaced when the object was deleted and created again since, or with 422 not_revertible; see Error codes. A revert that isn’t a dry run is in the audit log as revert.
Extensions
Section titled “Extensions”GET /api/v1/extensions returns the extensions file as KubeGlass has it now: { path, found, problems, actions, columns, aliases }. Entries with mistakes are left out and described in problems.
Setup mode
Section titled “Setup mode”While KubeGlass waits for a kubeconfig, it answers GET /healthz, GET /readyz (503), GET /api/v1/demo-config, POST /api/v1/setup/kubeconfig, which takes a kubeconfig and adds it, and POST /api/v1/setup/use-context with { context }, which makes one of the kubeconfig’s contexts the current one when it has contexts but no usable current one. Both take JSON from the machine KubeGlass runs on only. It answers every other /api/ and /ws/ request with 503 no_cluster. It answers only to localhost, names under .localhost, IP addresses and allowed_hosts.
Upgrade readiness
Section titled “Upgrade readiness”GET /api/v1/upgrade/readiness checks an upgrade of the control plane to the next minor version (targetVersion). deprecatedApis lists the deprecated API versions the cluster serves, each with when Kubernetes deprecates and removes it, what replaces it, and removedByTarget. The dates come from the lifecycle data in the k8s.io/api module KubeGlass is built with, so they cover every release up to latestStable. If you may read the API server’s /metrics, usageKnown is true and each entry says whether anything has requested it since the API server started. Deprecated versions the server reports that have no removal date, such as core v1 Endpoints, are included too. If you may list CustomResourceDefinitions, versions their CRDs mark deprecated are listed with custom set. nodes gives each kubelet’s skew (minor versions behind the control plane) and whether it stays supported after the upgrade.
Health
Section titled “Health”| Path | Answers |
|---|---|
GET /healthz, GET /livez |
200 while the process is up |
GET /readyz |
200 while the Kubernetes API server answers within 2 seconds, 503 otherwise and once shutdown begins. With prometheus_url set, the body also says whether that Prometheus answered its last check, run every 30 seconds; degraded doesn’t fail the probe |
GET /metrics |
Prometheus metrics for KubeGlass itself. Under a base path, at the root of the pod only; 404 with metrics_enabled: false |
WebSockets
Section titled “WebSockets”| Path | Carries |
|---|---|
/ws/watch |
Watch events for any resource type, each with a summary. A watch starts with a resource_watch_snapshot of every object and their summaries, and sends a new one if it has to list again because its resource version expired. Given the listVersion of a list from /api/v1/objects/…, it sends resource_watch_resumed instead when that list is still current, or watches on from the list’s resource version. fieldSelector=metadata.name=<name> watches one object |
/ws/logs |
Streaming container logs |
/ws/exec |
A shell in a container |
/ws/local-shell |
A shell on the server, when enabled |
WebSockets take as query parameters what HTTP requests send as headers: sid for the session, ctx for the cluster the client shows, cluster for another cluster the socket is for, ro=1 for a cluster marked read-only, and as and asGroup for Act As. A socket whose ctx isn’t its session’s cluster is closed with code 4409 and the reason context_mismatch: followed by the session’s cluster, or context_mismatch alone when the name doesn’t fit in the 123 bytes a close frame’s reason holds (an HTTP request then names it in its 409), and one whose cluster and X-KubeGlass-Cluster header name different clusters with 4400. A shell refused because KubeGlass or the cluster is read-only is closed with 4423, and a socket without a sign-in with 4401, whose reason is cookie_conflict when the browser sent more than one session cookie. An open socket closes with 4401 too when the sign-in it was opened with ends: the reason is signed_out when the person signed out, and session_ended when the session ran out or a new sign-in replaced it. Other refusals close with 4000 plus the HTTP status the request would have got, such as 4403 for Act As that isn’t allowed, and a reason that starts with the error code.
Endpoints
Section titled “Endpoints”Kubernetes resources
Section titled “Kubernetes resources”| Method | Path |
|---|---|
POST |
/api/v1/apply |
POST |
/api/v1/manifests/fetch |
POST |
/api/v1/projects/apply |
GET |
/api/v1/changes |
GET |
/api/v1/extensions |
GET |
/api/v1/extensions/file |
PUT |
/api/v1/extensions/file |
GET |
/api/v1/extensions/k9s |
POST |
/api/v1/extensions/validate |
GET |
/api/v1/clusterrolebindings/{name} |
GET |
/api/v1/clusterroles/{name} |
GET |
/api/v1/cronjobs |
GET |
/api/v1/daemonsets |
GET |
/api/v1/deployments |
GET |
/api/v1/events |
GET |
/api/v1/horizontalpodautoscalers |
GET |
/api/v1/ingresses |
GET |
/api/v1/objects/{group}/{version}/{resource} |
GET |
/api/v1/limitranges |
GET |
/api/v1/namespaces |
GET |
/api/v1/namespaces/{namespace}/cronjobs |
POST |
/api/v1/namespaces/{namespace}/cronjobs/{name}/resume |
POST |
/api/v1/namespaces/{namespace}/cronjobs/{name}/suspend |
POST |
/api/v1/namespaces/{namespace}/cronjobs/{name}/trigger |
GET |
/api/v1/namespaces/{namespace}/daemonsets |
GET |
/api/v1/namespaces/{namespace}/deployments |
POST |
/api/v1/namespaces/{namespace}/deployments/{name}/rollback |
GET |
/api/v1/namespaces/{namespace}/events |
GET |
/api/v1/namespaces/{namespace}/horizontalpodautoscalers |
GET |
/api/v1/namespaces/{namespace}/ingresses |
GET |
/api/v1/namespaces/{namespace}/limitranges |
GET |
/api/v1/namespaces/{namespace}/poddisruptionbudgets |
GET |
/api/v1/namespaces/{namespace}/pods |
GET |
/api/v1/namespaces/{namespace}/pods/{name}/env |
POST |
/api/v1/namespaces/{namespace}/pods/{pod}/debug |
POST |
/api/v1/namespaces/{namespace}/pods/{pod}/eviction |
GET |
/api/v1/namespaces/{namespace}/pods/{pod}/files |
GET |
/api/v1/namespaces/{namespace}/pods/{pod}/files/content |
GET |
/api/v1/namespaces/{namespace}/pods/{pod}/files/download |
POST |
/api/v1/namespaces/{namespace}/pods/{pod}/files/mkdir |
POST |
/api/v1/namespaces/{namespace}/pods/{pod}/files/upload |
GET |
/api/v1/namespaces/{namespace}/pods/{pod}/log |
POST |
/api/v1/namespaces/{namespace}/portforward |
GET |
/api/v1/namespaces/{namespace}/replicasets |
GET |
/api/v1/namespaces/{namespace}/services |
GET |
/api/v1/namespaces/{namespace}/statefulsets |
GET |
/api/v1/namespaces/{namespace}/{resource}/{name} (with summary) |
DELETE |
/api/v1/namespaces/{namespace}/{resource}/{name} |
PATCH |
/api/v1/namespaces/{namespace}/{resource}/{name}/metadata |
POST |
/api/v1/namespaces/{namespace}/{resource}/{name}/restart |
PUT |
/api/v1/namespaces/{namespace}/{resource}/{name}/scale |
PUT |
/api/v1/namespaces/{namespace}/{resource}/{name}/yaml |
POST |
/api/v1/namespaces/{namespace}/{resource}/{name}/revert |
GET |
/api/v1/namespaces/{name} |
GET |
/api/v1/namespaces/{ns}/resources/{kind}/{name}/dependencies |
GET |
/api/v1/nodes |
GET |
/api/v1/nodes/{name}/allocation |
GET |
/api/v1/nodes/{node} |
POST |
/api/v1/nodes/{node}/cordon |
POST |
/api/v1/nodes/{node}/drain |
GET |
/api/v1/nodes/{node}/drain |
DELETE |
/api/v1/nodes/{node}/drain |
POST |
/api/v1/nodes/{node}/shell |
POST |
/api/v1/nodes/{node}/taint |
DELETE |
/api/v1/nodes/{node}/taint/{key} |
POST |
/api/v1/nodes/{node}/uncordon |
GET |
/api/v1/persistentvolumes/{name} |
GET |
/api/v1/poddisruptionbudgets |
GET |
/api/v1/pods |
DELETE |
/api/v1/portforward/{id} |
GET |
/api/v1/portforwards |
GET |
/api/v1/replicasets |
GET |
/api/v1/resources |
GET |
/api/v1/resources/groups |
GET |
/api/v1/services |
GET |
/api/v1/statefulsets |
GET |
/api/v1/storageclasses/{name} |
GET |
/api/v1/xray/namespaces/{namespace}/{resource}/{name} |
GET |
/api/v1/xray/{resource}/{name} |
PATCH |
/api/v1/{resource}/{name}/metadata |
POST /api/v1/nodes/{node}/drain cordons the node and evicts its pods through the Eviction API, as kubectl drain --ignore-daemonsets --delete-emptydir-data does, and answers 202; GET on the same path follows it and DELETE stops it. The body can set ignoreDaemonSets, deleteEmptyDirData, force (also evict pods no controller recreates) and gracePeriodSeconds; without gracePeriodSeconds each pod gets its own terminationGracePeriodSeconds, as with kubectl.
PATCH …/{resource}/{name}/metadata takes { labels, annotations }, with null for a key to remove, and group= for a kind outside the core group, as a custom resource whose plural a built-in kind has too needs it (Knative’s services).
…/restart and …/deployments/{name}/rollback refuse a paused Deployment with 409 deployment_paused, as kubectl rollout restart and kubectl rollout undo do: its controller rolls out nothing until it is resumed.
GET /api/v1/nodes/{name}/allocation sums the requests and limits of the pods on the node, so it needs list on pods in all namespaces. Without it the answer is 403 with the API server’s reason, as for a node or pod (…/pods/{name}/env) you may not read.
GET …/pods/{name}/env?container= resolves the variables of a container, native sidecar or init container, sorted by name, each with its source and sourceDetail. A Secret’s value is never sent (masked). Where a name comes from several places, the one the container gets comes first and the others have overridden and, in overriddenBy, the sourceDetail that replaces them: an env entry replaces any envFrom value, and a later envFrom source an earlier one, as Kubernetes applies them. An optional configMapKeyRef or secretKeyRef whose ConfigMap, Secret or key isn’t there has unset and replaces nothing, as the kubelet skips it.
GET /api/v1/xray/… answers the tree of objects related to one. Pods, Deployments, StatefulSets, DaemonSets, ReplicaSets, Services, Ingresses, PersistentVolumeClaims and nodes get a tree; with group= (empty for the core group) only in their own group, so an object of another group with the same plural, such as a Knative Service, gets itself alone. Without group= the plural alone decides.
Cluster and contexts
Section titled “Cluster and contexts”| Method | Path |
|---|---|
GET |
/api/v1/cluster/health ({ healthy, status, state, consecutiveFailures, failingSince, lastCheck }: the background health check’s last result, degraded from the first failure and unreachable once the circuit breaker is open) |
GET |
/api/v1/cluster/info |
GET |
/api/v1/cluster/reach ({ reachable, version }, 200 either way: the connection check) |
GET |
/api/v1/cluster/{resource}/{name} (with summary) |
DELETE |
/api/v1/cluster/{resource}/{name} |
PUT |
/api/v1/cluster/{resource}/{name}/yaml |
POST |
/api/v1/connect/bootstrap |
POST |
/api/v1/connect/bulk |
DELETE |
/api/v1/connect/clusters/{name} |
POST |
/api/v1/connect/directory |
POST |
/api/v1/connect/kubeconfig (with directory and multi-kubeconfig: renamed, the entries saved under another name; warnings, what was left out, each a code of missing_cluster, missing_user, kubeconfig_user (a context pairs its file’s cluster with name, a user only the kubeconfig has), kubeconfig_cluster (a cluster only the kubeconfig has with its file’s user), unreadable, too_large or read_failed with its context, name, file or fileIndex and detail where they apply, and an English message; unchecked, how many were added unchecked for lack of time; each cluster with a statusCode that says why it isn’t connected, such as token_refused, unreachable or not_checked_plugin, with statusDetail (the cluster’s, the plugin’s or the network’s own words) or statusSeconds where they apply, and the English in statusMessage) |
GET |
/api/v1/connect/methods |
POST |
/api/v1/connect/multi-kubeconfig |
POST |
/api/v1/connect/serviceaccount |
POST |
/api/v1/connect/sso |
GET |
/api/v1/connect/sso/callback |
POST |
/api/v1/connect/sso/callback |
GET |
/api/v1/connect/sso/status |
POST |
/api/v1/connect/token (and the SSO callback: replaced, the contexts made before for the same user at the same server whose credentials were replaced) |
GET |
/api/v1/contexts |
GET |
/api/v1/contexts/health-summary |
GET |
/api/v1/contexts/problems |
GET |
/api/v1/contexts/{name}/diagnose |
PUT |
/api/v1/contexts/{name}/switch |
GET |
/api/v1/dashboard/summary |
GET |
/api/v1/demo-config |
GET |
/api/v1/fleet/health |
POST |
/api/v1/setup/kubeconfig (setup mode only) |
POST |
/api/v1/setup/use-context (setup mode only) |
Problems, map, checks and search
Section titled “Problems, map, checks and search”| Method | Path |
|---|---|
POST |
/api/v1/diagnose |
GET |
/api/v1/graph |
GET |
/api/v1/health-scan |
POST |
/api/v1/health-scan |
GET |
/api/v1/problems |
POST |
/api/v1/search |
GET |
/api/v1/timeline |
GET |
/api/v1/upgrade/readiness |
Metrics
Section titled “Metrics”| Method | Path |
|---|---|
GET |
/api/v1/metrics/alerts |
GET |
/api/v1/metrics/cluster |
GET |
/api/v1/metrics/history |
GET |
/api/v1/metrics/namespaces/{namespace}/pods |
GET |
/api/v1/metrics/namespaces/{namespace}/pods/{pod} |
POST |
/api/v1/metrics/query |
GET |
/api/v1/metrics/query/presets |
GET |
/api/v1/metrics/source |
GET |
/api/v1/rightsizing |
GET |
/api/v1/top/nodes |
GET |
/api/v1/top/pods |
Alerts
Section titled “Alerts”| Method | Path |
|---|---|
GET |
/api/v1/alertmanager/silences |
POST |
/api/v1/alertmanager/silences |
DELETE |
/api/v1/alertmanager/silences/{id} |
GET |
/api/v1/alertmanager/status |
Access and security
Section titled “Access and security”| Method | Path |
|---|---|
GET |
/api/v1/audit/events |
POST |
/api/v1/authz/can-i |
GET |
/api/v1/authz/identity |
GET |
/api/v1/authz/rules |
GET |
/api/v1/authz/whoami |
GET |
/api/v1/certificates |
GET |
/api/v1/images |
GET |
/api/v1/policy/violations |
GET |
/api/v1/rbac/bindings |
POST |
/api/v1/rbac/bindings |
GET |
/api/v1/rbac/matrix/{subject} |
GET |
/api/v1/rbac/roles |
POST |
/api/v1/rbac/roles |
GET |
/api/v1/rbac/who-can-access |
GET |
/api/v1/security/netpol-coverage |
GET |
/api/v1/vulnerabilities |
GET /api/v1/images takes namespace for one namespace or namespaces (comma-separated, at most 100) for several. With neither it reads the pods of the whole cluster, or, if you may not list them there, of the first 25 namespaces you can see, your kubeconfig context’s namespace first, eight at a time, and namespacesLeftOut counts the ones past those. skippedNamespaces names the namespaces whose pods you may not list. If you may list pods in none of them, the answer is 403.
| Method | Path |
|---|---|
GET |
/api/v1/helm/charts/latest |
GET |
/api/v1/helm/charts/readme |
GET |
/api/v1/helm/charts/values |
GET |
/api/v1/helm/charts/versions |
GET |
/api/v1/helm/operations/{id} |
GET |
/api/v1/helm/releases?namespace= |
POST |
/api/v1/helm/releases |
GET |
/api/v1/helm/releases/{namespace}/{name} |
PUT |
/api/v1/helm/releases/{namespace}/{name} |
DELETE |
/api/v1/helm/releases/{namespace}/{name} |
GET |
/api/v1/helm/releases/{namespace}/{name}/history |
POST |
/api/v1/helm/releases/{namespace}/{name}/rollback |
GET |
/api/v1/helm/releases/{namespace}/{name}/values |
GET |
/api/v1/helm/repos |
POST |
/api/v1/helm/repos |
POST |
/api/v1/helm/repos/update |
GET |
/api/v1/helm/repos/{name}/charts |
GET /api/v1/helm/releases/{namespace}/{name} (with ?revision= for an earlier one) answers with the release’s manifest and notes. In the manifest, and in a dry run’s manifest and hooks, each Secret value is a short hash of it (sha256:…), so two revisions, or a release and its upgrade’s dry run, still show which values changed. showValues=true on the GET shows the values where you may get Secrets. A Secret applied or saved through the YAML routes with such a hash as a value is refused with 422, as one with a value still REDACTED is.
An install (POST /api/v1/helm/releases), upgrade (PUT), rollback and uninstall (DELETE) runs in the background as an operation, { id, action, namespace, name, started, done, events }; a dry run answers with its result as before. With Prefer: respond-async the request answers 202 at once with the operation and a Location header. Without it, the request waits for the operation until just before its route’s deadline and answers what it did before operations: the result with 201 or 200, or the error with its status and code; an operation still running then answers 202 with a Location header, so a client that takes any 2xx as done (curl -f) must follow it until the operation is done. GET /api/v1/helm/operations/{id} follows it: once done it has result (what the request answers) or error with the code and status the request would have answered. Send operationId in the body (?operation= for an uninstall) to name it, or use the id in the answer. An ID in use answers 409 conflict; a user may run 16 operations at a time (429 too_many_helm_operations), and all users 1024 (503). Only the user who started an operation may read it, for 10 minutes after it ends; after a restart of KubeGlass it is gone (404), and how it ended is in the release’s history. Helm waits at most 30 minutes (timeout, in seconds, 300 by default). Adding a repository under a name another URL has answers 409 repo_name_taken; the same name and URL again answer status: "exists" after its index is downloaded again, and with other credentials in the URL status: "updated", once the index downloads with them. With sign-in, adding repositories and updating their indexes is for admins.
GitOps and rollouts
Section titled “GitOps and rollouts”| Method | Path |
|---|---|
GET |
/api/v1/gitops/providers |
GET |
/api/v1/gitops/providers/apps |
GET |
/api/v1/gitops/providers/apps/{namespace}/{name}/events |
GET |
/api/v1/gitops/providers/apps/{namespace}/{name}/history |
POST |
/api/v1/gitops/providers/apps/{namespace}/{name}/refresh |
POST |
/api/v1/gitops/providers/apps/{namespace}/{name}/rollback |
POST |
/api/v1/gitops/providers/apps/{namespace}/{name}/sync |
POST |
/api/v1/gitops/providers/apps/{namespace}/{name}/terminate |
GET |
/api/v1/gitops/providers/apps/{namespace}/{name}/tree |
GET |
/api/v1/gitops/providers/clusters |
GET |
/api/v1/gitops/providers/ownership |
POST |
/api/v1/gitops/providers/refresh |
GET |
/api/v1/gitops/providers/sources |
GET |
/api/v1/gitops/providers/topology |
GET |
/api/v1/rollouts |
POST |
/api/v1/rollouts/{namespace}/{name}/abort |
POST |
/api/v1/rollouts/{namespace}/{name}/promote |
POST |
/api/v1/rollouts/{namespace}/{name}/restart |
POST |
/api/v1/rollouts/{namespace}/{name}/retry |
GET /api/v1/gitops/providers/apps, …/sources, …/clusters and …/topology list as you what every Argo CD and Flux installation lists. When an installation’s list fails, in all or in part (Flux lists Kustomizations and HelmReleases apart, and its source kinds), the answer has what the others listed and failed, one { instanceId, provider, status, message, partial } per installation: status is the API server’s (403 when you may not list the kind), 504 when it didn’t answer in time or 502 when it couldn’t be reached, message the API server’s words, one kind’s after another’s, and partial is true when the installation listed some of its kinds. When every installation failed and none could list any of its kinds, …/apps, …/sources and …/clusters answer that status instead, 403 forbidden when every one was refused, with failed beside error and message. An installation that listed one of its kinds, even with nothing in it, has listed: a Flux installation that may list Kustomizations and not HelmReleases gets 200 with failed. …/topology always answers 200, with the controllers, which discovery finds, whatever their lists answered, the applications and clusters it could list, and failed. A kind the cluster doesn’t serve, such as HelmReleases without helm-controller, is no failure. The routes under …/apps/{namespace}/{name} take instance=, the application’s instanceId, and kind=, its rawKind (Application, Kustomization or HelmRelease): a Flux Kustomization and HelmRelease can share a namespace and name, and without kind they act on the Kustomization. POST …/rollback?revision=<id> rolls an Argo CD application back to the history entry with that id (from …/history), as argocd app rollback does, and prunes only with prune=true. Argo CD’s record of a sync or rollback names the signed-in user. An action Argo CD or Flux rules out answers 409 conflict with what to do instead: a sync or rollback while another operation runs, a rollback while auto-sync is on, terminate with no sync running or on Flux (which can’t stop a reconcile), force on a Flux Kustomization, and sync or refresh on a suspended Flux Kustomization or HelmRelease, which Flux doesn’t reconcile until it is resumed. On a HelmRelease, force sets reconcile.fluxcd.io/forceAt. A multi-source Argo CD application’s repoURL, path, chart, targetRef and revision are its first source’s, and sources lists them all, each with the revision it was synced to and its ref. A Flux HelmRelease’s history is its Helm releases (helm-controller v2’s status.history), with Helm’s release number as id and the release’s status as message.
The rollout actions make the changes kubectl argo rollouts makes, which the Argo Rollouts controller reads: abort sets status.abort, retry clears it, and promote clears the pause (status.pauseConditions, and spec.paused when the Rollout was paused by hand) or, mid-analysis, moves to the next step. promote with { "full": true } sets status.promoteFull, which skips the remaining steps and analyses. They patch the status subresource, or the Rollout itself where Rollouts have none (before v0.10), and a refusal keeps its status: 403 for RBAC, 404 for a Rollout that isn’t there. restart sets spec.restartAt. GET /api/v1/rollouts takes namespace for one namespace or namespaces (comma-separated, at most 100, listed eight at a time) for several, where skippedNamespaces names those you may not list Rollouts in. It answers an empty list when Argo Rollouts isn’t installed and 403 with the API server’s reason when you may not list Rollouts where it looked.
Multiple clusters and drift
Section titled “Multiple clusters and drift”| Method | Path |
|---|---|
POST |
/api/v1/cross-cluster/compare |
POST |
/api/v1/cross-cluster/diff |
POST |
/api/v1/cross-cluster/drift |
POST |
/api/v1/cross-cluster/rbac-diff |
POST |
/api/v1/cross-cluster/search |
The cross-cluster endpoints read each cluster as you. Under Act As, only the session’s cluster is read as that identity.
POST /api/v1/cross-cluster/diff answers an object only one cluster has with 404 not_found_in_source or not_found_in_target, and one neither has with 404 not_found, each naming the clusters; a cluster that refuses the read answers 403 naming it. When one cluster lacks the object and the other refused the read (403) or couldn’t be read (502), the code is source_missing_target_unread or target_missing_source_unread: only the first is known. POST /api/v1/cross-cluster/compare gives each cluster that gave nothing a reason beside its error, as the drift report’s errors do.
POST /api/v1/cross-cluster/drift reports an object of the reference that a target lacks as an item with missingInTarget: true and no differences, apart from objects a controller owns. It names every list that failed in errors ([{ cluster, reference, resource, namespace, reason, message }], reason one of forbidden, not_installed, no_answer, refused_credentials, no_clients and failed), and nothing in a list that failed counts as missing. A target that doesn’t answer is named once, without resource. When the reference can’t be read for any of the kinds asked for, or doesn’t answer, it answers 403 or 502 reference_unreadable.
| Method | Path |
|---|---|
GET |
/api/v1/drift/policies |
POST |
/api/v1/drift/policies |
DELETE |
/api/v1/drift/policies/{id} |
POST |
/api/v1/drift/policies/{id}/run |
GET |
/api/v1/drift/results |
POST |
/api/v1/drift/scan |
GET /api/v1/drift/policies gives a policy whose schedule can’t run, which an earlier KubeGlass may have saved, a scheduleError that says why. POST /api/v1/drift/policies answers 400 validation_error for a schedule that is neither a five-field cron expression nor a descriptor (@hourly, @daily, @weekly, @monthly, @yearly), with what is wrong in message, and for targetClusters that name no cluster but the reference, which it leaves out of them. It drops spaces around the schedule before saving it; one of only spaces is no schedule. A scan (POST /api/v1/drift/scan, POST /api/v1/drift/policies/{id}/run) runs for up to 55 seconds. Its result names the target clusters it didn’t scan, with why, in unscanned ([{ cluster, reason }]); their findings are missing. When the reference cluster, or every target, wasn’t scanned in time, it answers 504 scan_timeout.
Settings
Section titled “Settings”| Method | Path |
|---|---|
GET |
/api/v1/me/clusters |
PUT |
/api/v1/me/clusters/{cluster} |
PUT |
/api/v1/me/clusters/{cluster}/namespaces |
GET |
/api/v1/settings |
PUT |
/api/v1/settings |
GET |
/api/v1/settings/clusters |
PUT |
/api/v1/settings/clusters/{cluster} |
POST |
/api/v1/settings/test-webhook |