K8s API
Available in Freelens 1.8+
The K8s API provides extensions with the ability to perform Kubernetes operations on any cluster by ID, without switching the UI context. This enables building multi-cluster extensions that can query, create, update, and delete resources across clusters.
Quick Start
import { K8s, Catalog } from "@freelensapp/core/renderer";
// Get pods from a specific cluster
const cluster = Catalog.getActiveCluster();
const pods = await K8s.queryCluster(cluster.id, {
apiVersion: "v1",
kind: "Pod",
namespace: "default",
});
console.log(`Found ${pods.length} pods`);
Renderer API
queryCluster()
List resources from a specific cluster.
const pods = await K8s.queryCluster<Pod>(clusterId, {
apiVersion: "v1",
kind: "Pod",
namespace: "default",
labelSelector: "app=nginx", // optional
});
queryClusters()
Query multiple clusters in parallel.
const results = await K8s.queryClusters<Pod>([clusterId1, clusterId2], {
apiVersion: "v1",
kind: "Pod",
namespace: "default",
});
for (const [clusterId, data] of results) {
if (data instanceof Error) {
console.error(`Cluster ${clusterId} failed:`, data.message);
} else {
console.log(`Cluster ${clusterId}: ${data.length} pods`);
}
}
queryAllClusters()
Query all connected clusters.
const results = await K8s.queryAllClusters<Node>({
apiVersion: "v1",
kind: "Node",
});
for (const [clusterId, data] of results) {
if (!(data instanceof Error)) {
console.log(`Cluster ${clusterId}: ${data.length} nodes`);
}
}
getResource()
Get a single resource by name.
const pod = await K8s.getResource<Pod>(clusterId, {
apiVersion: "v1",
kind: "Pod",
namespace: "default",
name: "my-pod",
});
if (pod) {
console.log(`Pod status: ${pod.status?.phase}`);
}
applyOnCluster()
Create or update a resource.
await K8s.applyOnCluster(clusterId, {
apiVersion: "v1",
kind: "ConfigMap",
metadata: { name: "my-config", namespace: "default" },
data: { key: "value" },
});
deleteOnCluster()
Delete a resource.
await K8s.deleteOnCluster(clusterId, {
apiVersion: "v1",
kind: "Pod",
namespace: "default",
name: "my-pod",
});
patchOnCluster()
Patch a resource using strategic merge, JSON merge, or JSON patch.
// Strategic merge patch (default)
await K8s.patchOnCluster(
clusterId,
{
apiVersion: "apps/v1",
kind: "Deployment",
namespace: "default",
name: "my-app",
},
{ spec: { replicas: 3 } },
"strategic",
);
// JSON merge patch
await K8s.patchOnCluster(
clusterId,
{
apiVersion: "v1",
kind: "ConfigMap",
namespace: "default",
name: "my-config",
},
{ data: { newKey: "newValue" } },
"merge",
);
// JSON patch
await K8s.patchOnCluster(
clusterId,
{ apiVersion: "v1", kind: "Pod", namespace: "default", name: "my-pod" },
[{ op: "add", path: "/metadata/labels/patched", value: "true" }],
"json",
);
Main API
The main process API provides all the same functions:
K8s.queryCluster()K8s.queryClusters()K8s.queryAllClusters()K8s.getResource()K8s.applyOnCluster()K8s.deleteOnCluster()K8s.patchOnCluster()
Types
ClusterId
All functions accept a ClusterId type for the cluster identifier. Import it from K8s and get values from the Catalog API:
import { K8s, Catalog } from "@freelensapp/core/renderer";
import type { ClusterId } from "@freelensapp/core/renderer";
const cluster = Catalog.getActiveCluster();
const clusterId: ClusterId = cluster.id; // ClusterInfo.id is typed as ClusterId
Or more simply, since ClusterInfo.id is already typed as ClusterId:
import { K8s, Catalog } from "@freelensapp/core/renderer";
const cluster = Catalog.getActiveCluster();
const pods = await K8s.queryCluster(cluster.id, { ... }); // cluster.id is ClusterId
ResourceQuery
interface ResourceQuery {
apiVersion: string; // e.g., "v1", "apps/v1"
kind: string; // e.g., "Pod", "Deployment"
namespace?: string; // required for namespaced resources
name?: string; // for single-resource operations
labelSelector?: string; // e.g., "app=nginx,env=prod"
fieldSelector?: string; // e.g., "status.phase=Running"
}
KubeApiPatchType
Error Handling
Single-cluster operations throw errors on failure:
try {
await K8s.queryCluster(clusterId, query);
} catch (error) {
console.error("Query failed:", error.message);
}
Multi-cluster operations (queryClusters, queryAllClusters) return per-cluster results:
const results = await K8s.queryClusters(clusterIds, query);
for (const [id, data] of results) {
if (data instanceof Error) {
console.error(`Cluster ${id}:`, data.message);
} else {
console.log(`Cluster ${id}: ${data.length} items`);
}
}
Cluster must be connected
Operations will fail with an error if the target cluster is not connected. Check cluster.status === ClusterConnectionStatus.CONNECTED before making API calls.
Namespace is required for namespaced resources
Always include namespace in your query for namespaced resources like Pods, Deployments, and ConfigMaps. Cluster-scoped resources like Nodes and Namespaces don't require it.