Skip to content

Commit 2bf97b4

Browse files
authored
Merge pull request #2 from omarluq/k8s-api
document k8s api
2 parents 8455d33 + 9d95049 commit 2bf97b4

3 files changed

Lines changed: 267 additions & 1 deletion

File tree

docs/extensions/main/catalog-api.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,25 @@ The main process API provides:
5959

6060
## Types
6161

62+
### ClusterId
63+
64+
A type alias for cluster identifiers. Use this with the [K8s API](./k8s-api.md) to perform operations on clusters:
65+
66+
```typescript
67+
import { Catalog, K8s, ClusterId } from "@freelensapp/core/renderer";
68+
69+
const cluster = Catalog.getActiveCluster();
70+
const clusterId: ClusterId = cluster.id;
71+
72+
// Use with K8s API
73+
const pods = await K8s.queryCluster(clusterId, { apiVersion: "v1", kind: "Pod" });
74+
```
75+
6276
### ClusterInfo
6377

6478
```typescript
6579
interface ClusterInfo {
66-
readonly id: string;
80+
readonly id: ClusterId; // Use with K8s API
6781
readonly name: string;
6882
readonly kubeConfigPath: string;
6983
readonly contextName: string;

docs/extensions/main/k8s-api.md

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
# K8s API
2+
3+
!!! info "Available in Freelens 1.8+"
4+
5+
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.
6+
7+
## Quick Start
8+
9+
```typescript
10+
import { K8s, Catalog } from "@freelensapp/core/renderer";
11+
12+
// Get pods from a specific cluster
13+
const cluster = Catalog.getActiveCluster();
14+
const pods = await K8s.queryCluster(cluster.id, {
15+
apiVersion: "v1",
16+
kind: "Pod",
17+
namespace: "default",
18+
});
19+
20+
console.log(`Found ${pods.length} pods`);
21+
```
22+
23+
## Renderer API
24+
25+
```typescript
26+
import { K8s } from "@freelensapp/core/renderer";
27+
```
28+
29+
### queryCluster()
30+
31+
List resources from a specific cluster.
32+
33+
```typescript
34+
const pods = await K8s.queryCluster<Pod>(clusterId, {
35+
apiVersion: "v1",
36+
kind: "Pod",
37+
namespace: "default",
38+
labelSelector: "app=nginx", // optional
39+
});
40+
```
41+
42+
### queryClusters()
43+
44+
Query multiple clusters in parallel.
45+
46+
```typescript
47+
const results = await K8s.queryClusters<Pod>([clusterId1, clusterId2], {
48+
apiVersion: "v1",
49+
kind: "Pod",
50+
namespace: "default",
51+
});
52+
53+
for (const [clusterId, data] of results) {
54+
if (data instanceof Error) {
55+
console.error(`Cluster ${clusterId} failed:`, data.message);
56+
} else {
57+
console.log(`Cluster ${clusterId}: ${data.length} pods`);
58+
}
59+
}
60+
```
61+
62+
### queryAllClusters()
63+
64+
Query all connected clusters.
65+
66+
```typescript
67+
const results = await K8s.queryAllClusters<Node>({
68+
apiVersion: "v1",
69+
kind: "Node",
70+
});
71+
72+
for (const [clusterId, data] of results) {
73+
if (!(data instanceof Error)) {
74+
console.log(`Cluster ${clusterId}: ${data.length} nodes`);
75+
}
76+
}
77+
```
78+
79+
### getResource()
80+
81+
Get a single resource by name.
82+
83+
```typescript
84+
const pod = await K8s.getResource<Pod>(clusterId, {
85+
apiVersion: "v1",
86+
kind: "Pod",
87+
namespace: "default",
88+
name: "my-pod",
89+
});
90+
91+
if (pod) {
92+
console.log(`Pod status: ${pod.status?.phase}`);
93+
}
94+
```
95+
96+
### applyOnCluster()
97+
98+
Create or update a resource.
99+
100+
```typescript
101+
await K8s.applyOnCluster(clusterId, {
102+
apiVersion: "v1",
103+
kind: "ConfigMap",
104+
metadata: { name: "my-config", namespace: "default" },
105+
data: { key: "value" },
106+
});
107+
```
108+
109+
### deleteOnCluster()
110+
111+
Delete a resource.
112+
113+
```typescript
114+
await K8s.deleteOnCluster(clusterId, {
115+
apiVersion: "v1",
116+
kind: "Pod",
117+
namespace: "default",
118+
name: "my-pod",
119+
});
120+
```
121+
122+
### patchOnCluster()
123+
124+
Patch a resource using strategic merge, JSON merge, or JSON patch.
125+
126+
```typescript
127+
// Strategic merge patch (default)
128+
await K8s.patchOnCluster(
129+
clusterId,
130+
{
131+
apiVersion: "apps/v1",
132+
kind: "Deployment",
133+
namespace: "default",
134+
name: "my-app",
135+
},
136+
{ spec: { replicas: 3 } },
137+
"strategic",
138+
);
139+
140+
// JSON merge patch
141+
await K8s.patchOnCluster(
142+
clusterId,
143+
{
144+
apiVersion: "v1",
145+
kind: "ConfigMap",
146+
namespace: "default",
147+
name: "my-config",
148+
},
149+
{ data: { newKey: "newValue" } },
150+
"merge",
151+
);
152+
153+
// JSON patch
154+
await K8s.patchOnCluster(
155+
clusterId,
156+
{ apiVersion: "v1", kind: "Pod", namespace: "default", name: "my-pod" },
157+
[{ op: "add", path: "/metadata/labels/patched", value: "true" }],
158+
"json",
159+
);
160+
```
161+
162+
## Main API
163+
164+
```typescript
165+
import { K8s } from "@freelensapp/core/main";
166+
```
167+
168+
The main process API provides all the same functions:
169+
170+
- `K8s.queryCluster()`
171+
- `K8s.queryClusters()`
172+
- `K8s.queryAllClusters()`
173+
- `K8s.getResource()`
174+
- `K8s.applyOnCluster()`
175+
- `K8s.deleteOnCluster()`
176+
- `K8s.patchOnCluster()`
177+
178+
## Types
179+
180+
### ClusterId
181+
182+
All functions accept a `ClusterId` type for the cluster identifier. Import it from `K8s` and get values from the Catalog API:
183+
184+
```typescript
185+
import { K8s, Catalog } from "@freelensapp/core/renderer";
186+
import type { ClusterId } from "@freelensapp/core/renderer";
187+
188+
const cluster = Catalog.getActiveCluster();
189+
const clusterId: ClusterId = cluster.id; // ClusterInfo.id is typed as ClusterId
190+
```
191+
192+
Or more simply, since `ClusterInfo.id` is already typed as `ClusterId`:
193+
194+
```typescript
195+
import { K8s, Catalog } from "@freelensapp/core/renderer";
196+
197+
const cluster = Catalog.getActiveCluster();
198+
const pods = await K8s.queryCluster(cluster.id, { ... }); // cluster.id is ClusterId
199+
```
200+
201+
### ResourceQuery
202+
203+
```typescript
204+
interface ResourceQuery {
205+
apiVersion: string; // e.g., "v1", "apps/v1"
206+
kind: string; // e.g., "Pod", "Deployment"
207+
namespace?: string; // required for namespaced resources
208+
name?: string; // for single-resource operations
209+
labelSelector?: string; // e.g., "app=nginx,env=prod"
210+
fieldSelector?: string; // e.g., "status.phase=Running"
211+
}
212+
```
213+
214+
### KubeApiPatchType
215+
216+
```typescript
217+
type KubeApiPatchType = "strategic" | "merge" | "json";
218+
```
219+
220+
## Error Handling
221+
222+
Single-cluster operations throw errors on failure:
223+
224+
```typescript
225+
try {
226+
await K8s.queryCluster(clusterId, query);
227+
} catch (error) {
228+
console.error("Query failed:", error.message);
229+
}
230+
```
231+
232+
Multi-cluster operations (`queryClusters`, `queryAllClusters`) return per-cluster results:
233+
234+
```typescript
235+
const results = await K8s.queryClusters(clusterIds, query);
236+
237+
for (const [id, data] of results) {
238+
if (data instanceof Error) {
239+
console.error(`Cluster ${id}:`, data.message);
240+
} else {
241+
console.log(`Cluster ${id}: ${data.length} items`);
242+
}
243+
}
244+
```
245+
246+
!!! warning "Cluster must be connected"
247+
Operations will fail with an error if the target cluster is not connected. Check `cluster.status === ClusterConnectionStatus.CONNECTED` before making API calls.
248+
249+
!!! tip "Namespace is required for namespaced resources"
250+
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.
251+

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ nav:
4545
- Entity Settings: extensions/main/entity-settings.md
4646
- KubeObject Detail Items: extensions/main/kube-object-detail-items.md
4747
- Catalog API: extensions/main/catalog-api.md
48+
- K8s API: extensions/main/k8s-api.md
4849
plugins:
4950
- blog
5051
- search

0 commit comments

Comments
 (0)