Skip to content

Commit c25069c

Browse files
authored
Create API layer to consume k8s resources - part 1 (#16895)
* wip * cover 'list', 'listAll', 'get' and 'labelSelector' methods * docusaurus updates missed from last commit * fix docusaurus build * address pr comments * fix unit tests * address pr comments + fixed examples of shell api to be composition api first + updated methods and naming used for resources API + update tests * address pr comments from cody * address pr comments from richard * address final comments * fix issue with findFiltered around usage and types + update unit tests and docs * fix return types of findFiltered + fix lint issues * fix lint issues
1 parent 85804a9 commit c25069c

31 files changed

Lines changed: 1659 additions & 95 deletions

docusaurus/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
# Typedoc integration
1212
docs/extensions/shell-api
13+
docs/extensions/resources-api
1314

1415
# Misc
1516
.DS_Store
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
---
2+
id: resources-api
3+
---
4+
5+
# Resources API (Experimental)
6+
7+
> Note: This API is experimental and may change in future releases. Available from Rancher `2.15` and onwards
8+
9+
## What is the Resources API?
10+
11+
The Resources API helps extension developers interact with Kubernetes and Rancher resources programmatically. This API provides a type-safe interface for common resource operations such as listing, retrieving, and filtering resources with full TypeScript support and autocomplete.
12+
13+
The API is organized into two contexts:
14+
15+
- **Cluster Context** (`cluster`) - For cluster-scoped Kubernetes resources (Pods, Deployments, Services, etc.)
16+
- **Management Context** (`mgmt`) - For global Rancher resources (Users, Clusters, Settings, etc.)
17+
18+
Both contexts implement the same base `ResourcesApi` interface, so they share the same methods (`find`, `findFiltered`, `findAll`).
19+
20+
## How to use the Resources API
21+
22+
### Using Options API in Vue
23+
24+
To use the Resources API in the context of the **Options API** of a Vue component, we globally expose the `$resources` property, which is available under the `this` object:
25+
26+
```ts
27+
import { K8S } from '@shell/apis';
28+
29+
export default {
30+
async mounted() {
31+
// Cluster context
32+
const pods = await this.$resources.cluster.findFiltered(K8S.POD);
33+
34+
// Management context
35+
const users = await this.$resources.mgmt.findFiltered(K8S.USER);
36+
}
37+
}
38+
```
39+
40+
### Using Composition API in Vue
41+
42+
To use the Resources API in the context of the **Composition API** of a Vue component, we'll need to import the correct method to make the API available in the component:
43+
44+
```ts
45+
import { useResources } from '@shell/apis';
46+
```
47+
48+
then just assign to a constant in the context for your component and use it:
49+
50+
```ts
51+
import { useResources, K8S } from '@shell/apis';
52+
53+
const resources = useResources();
54+
55+
// Cluster context - for cluster-scoped resources
56+
const pods = await resources.cluster.findFiltered(K8S.POD);
57+
const deployment = await resources.cluster.find(K8S.DEPLOYMENT, 'default/my-app');
58+
59+
// Management context - for global resources
60+
const users = await resources.mgmt.findFiltered(K8S.USER);
61+
const user = await resources.mgmt.find(K8S.USER, 'u-xyz789');
62+
```
63+
64+
## Resource Constants
65+
66+
The `K8S` object contains constants for common Kubernetes and Rancher resources:
67+
68+
```ts
69+
import { K8S } from '@shell/apis';
70+
71+
// Core Kubernetes resources
72+
K8S.POD
73+
K8S.SERVICE
74+
K8S.CONFIG_MAP
75+
K8S.SECRET
76+
K8S.NAMESPACE
77+
K8S.NODE
78+
79+
// Workload resources
80+
K8S.DEPLOYMENT
81+
K8S.STATEFUL_SET
82+
K8S.DAEMON_SET
83+
84+
// Rancher Management
85+
K8S.USER
86+
K8S.PROJECT
87+
K8S.GLOBAL_ROLE
88+
89+
// And many more...
90+
```
91+
92+
For custom resources or CRDs, you can use strings directly:
93+
94+
```ts
95+
const customResources = await resources.cluster.findFiltered('mycompany.io.customresource');
96+
```
97+
98+
## Available API's
99+
100+
| API | Description |
101+
| :--- | :--- |
102+
| [Cluster API](./resources-api/interfaces/ClusterApi) | Interact with cluster-scoped Kubernetes resources (Pods, Deployments, Services, etc.) |
103+
| [Management API](./resources-api/interfaces/MgmtApi) | Interact with global Rancher resources (Users, Clusters, Settings, etc.) |

docusaurus/docusaurus.config.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ const config = {
5656
// show params as code blocks
5757
useCodeBlocks: true,
5858

59+
// render nested object sub-properties as a compact HTML table
60+
// instead of separate heading blocks (improves visual hierarchy)
61+
propertyMembersFormat: 'htmlTable',
62+
5963
// The entry point for TypeDoc to start scanning for files.
6064
// The path is relative to the `docusaurus` directory.
6165
// entryPoints: ['../shell/apis/shell/*'],
@@ -90,6 +94,24 @@ const config = {
9094
excludeInternal: true
9195
},
9296
],
97+
[
98+
'docusaurus-plugin-typedoc',
99+
{
100+
disableSources: true,
101+
textContentMappings: { 'title.memberPage': '{name}' },
102+
useCodeBlocks: true,
103+
propertyMembersFormat: 'htmlTable',
104+
entryPoints: ['../shell/apis/intf/resources.ts'],
105+
tsconfig: 'tsconfig-typedoc-integration.json',
106+
out: 'docs/extensions/resources-api',
107+
readme: 'none',
108+
cleanOutputDir: false,
109+
sidebar: { autoConfiguration: true },
110+
entryFileName: '_api-index.md',
111+
id: 'resources-api-docs',
112+
excludeInternal: true
113+
},
114+
],
93115
[require.resolve('docusaurus-lunr-search'), { excludeRoutes: ['internal/*', 'internal/**/*', '/internal/*', '/internal/**/*', 'blog/*', 'blog/**/*', '/blog/*', '/blog/**/*'] }
94116
],
95117
[

docusaurus/extensionSidebar.js

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
const fs = require('fs');
22
const path = require('path');
33

4-
// Define the absolute path to the sidebar file that `docusaurus-plugin-typedoc` generates.
5-
const typedocSidebarPath = path.resolve(__dirname, './docs/extensions/shell-api/typedoc-sidebar.cjs');
4+
// Define the absolute paths to the sidebar files that `docusaurus-plugin-typedoc` generates.
5+
const shellApiSidebarPath = path.resolve(__dirname, './docs/extensions/shell-api/typedoc-sidebar.cjs');
6+
const resourcesApiSidebarPath = path.resolve(__dirname, './docs/extensions/resources-api/typedoc-sidebar.cjs');
67

78
/**
89
* Recursively processes an array of Docusaurus sidebar items.
@@ -49,17 +50,22 @@ function fixTypedocIds(items) {
4950
});
5051
}
5152

52-
// Initialize an empty array for the TypeDoc sidebar items.
53-
let typedocSidebarItems = [];
53+
// Initialize empty arrays for both TypeDoc sidebar items.
54+
let shellApiSidebarItems = [];
55+
let resourcesApiSidebarItems = [];
5456

55-
// Safely check if the generated `typedoc-sidebar.cjs` file exists.
56-
// This prevents build errors if the file hasn't been generated yet.
57-
if (fs.existsSync(typedocSidebarPath)) {
58-
// If the file exists, import its contents.
59-
const originalTypedocSidebar = require(typedocSidebarPath);
57+
// Load Shell API sidebar
58+
if (fs.existsSync(shellApiSidebarPath)) {
59+
const originalShellApiSidebar = require(shellApiSidebarPath);
6060

61-
// Run the imported items through our correction function.
62-
typedocSidebarItems = fixTypedocIds(originalTypedocSidebar);
61+
shellApiSidebarItems = fixTypedocIds(originalShellApiSidebar);
62+
}
63+
64+
// Load Resources API sidebar
65+
if (fs.existsSync(resourcesApiSidebarPath)) {
66+
const originalResourcesApiSidebar = require(resourcesApiSidebarPath);
67+
68+
resourcesApiSidebarItems = fixTypedocIds(originalResourcesApiSidebar);
6369
}
6470

6571
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
@@ -127,7 +133,16 @@ const sidebars = {
127133
type: 'doc',
128134
id: 'shell-api',
129135
},
130-
items: typedocSidebarItems
136+
items: shellApiSidebarItems
137+
},
138+
{
139+
type: 'category',
140+
label: 'Resources API (Experimental)',
141+
link: {
142+
type: 'doc',
143+
id: 'resources-api',
144+
},
145+
items: resourcesApiSidebarItems
131146
},
132147
{
133148
type: 'category',

docusaurus/src/css/custom.css

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,36 @@ h5.anchor {
189189
text-decoration: underline;
190190
}
191191

192+
/* Make "Inherited from" sections footnote-style */
193+
h4[id^="inherited-from"],
194+
h5[id^="inherited-from"] {
195+
font-size: 0.85rem;
196+
font-weight: normal;
197+
color: var(--ifm-color-emphasis-600);
198+
margin-top: 0.35rem;
199+
margin-bottom: 0.2rem;
200+
}
201+
202+
h4[id^="inherited-from"] + div pre,
203+
h5[id^="inherited-from"] + div pre {
204+
font-size: 0.8rem;
205+
padding: 0.15rem 0.4rem;
206+
background: transparent;
207+
border: none;
208+
box-shadow: none;
209+
margin-top: 0;
210+
margin-bottom: 0.5rem;
211+
background-color: transparent !important;
212+
}
213+
214+
h4[id^="inherited-from"] + div pre code,
215+
h5[id^="inherited-from"] + div pre code {
216+
font-size: 0.8rem;
217+
background: transparent;
218+
color: var(--ifm-color-emphasis-600);
219+
padding: 0.10rem;
220+
}
221+
192222
@media screen and (max-width: 996px) {
193223
.homepage-banner {
194224
padding: 30px 30px;

docusaurus/tsconfig-typedoc-integration.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66
"target": "es6",
77
"esModuleInterop": true,
88
"skipLibCheck": true,
9-
"typeRoots": ["./node_modules/@types"],
9+
"typeRoots": [
10+
"./node_modules/@types"
11+
],
12+
"types": []
1013
},
11-
"include": [
12-
"../shell/apis/intf/shell.ts"
14+
"files": [
15+
"../shell/apis/intf/shell.ts",
16+
"../shell/apis/intf/resources.ts"
1317
],
1418
"exclude": [
1519
"node_modules"

shell/apis/impl/apis.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { throttle } from 'lodash';
22
import { createExtensionManager } from '@shell/core/extension-manager-impl';
33
import { ShellApiImpl } from '@shell/apis/shell';
4+
import { ResourcesApiImpl } from '@shell/apis/resources';
45

56
/**
67
* Initialise the APIs that are available in the shell
@@ -21,6 +22,11 @@ export function initUiApis(context: any, inject: any, vueApp: any) {
2122
// Shell API
2223
// ======================================================================================================================
2324
registerApi('shell', new ShellApiImpl(context.store), inject, vueApp);
25+
26+
// ======================================================================================================================
27+
// Resources API
28+
// ======================================================================================================================
29+
registerApi('resources', new ResourcesApiImpl(context.store), inject, vueApp);
2430
}
2531

2632
// ======================================================================================================================

shell/apis/index.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
import { inject } from 'vue';
44
import { ExtensionManager } from '@shell/types/extension-manager';
55
import { ShellApi as ShellApiImport } from '@shell/apis/intf/shell';
6+
import { ResourcesApiProvider as ResourcesApiProviderImport } from '@shell/apis/intf/resources';
67

78
// Re-export the types for the APIs, so they appear in this module
89
export type ShellApi = ShellApiImport;
10+
export type ResourcesApiProvider = ResourcesApiProviderImport;
911
export type ExtensionManagerApi = ExtensionManager;
1012

13+
// Re-export resource types and constants
14+
export * from '@shell/apis/intf/resources';
15+
1116
/**
1217
* Returns an object that can be used to access the registered extension manager instance.
1318
*
@@ -26,6 +31,27 @@ export const useShell = (): ShellApi => {
2631
return getApi<ShellApi>('$shell', 'useShell');
2732
};
2833

34+
/**
35+
* Returns an object that implements the ResourcesApiProvider interface.
36+
* Provides type-safe access to cluster and management resources.
37+
*
38+
* @returns Returns an object that implements the ResourcesApiProvider interface
39+
*
40+
* @example
41+
* ```ts
42+
* import { useResources, K8S } from '@shell/apis';
43+
*
44+
* // Cluster-scoped resources (current cluster context)
45+
* const pod = await resources.cluster.find(K8S.POD, 'default/my-pod-123');
46+
*
47+
* // Management/global resources
48+
* const user = await resources.mgmt.find(K8S.USER, 'u-xyz789');
49+
* ```
50+
*/
51+
export const useResources = (): ResourcesApiProvider => {
52+
return getApi<ResourcesApiProvider>('$resources', 'useResources');
53+
};
54+
2955
// =================================================================================================================
3056
// Internal helper to get any API by key with error handling
3157
// =================================================================================================================
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ResourcesApi } from './resources-api';
2+
3+
/**
4+
* @interface
5+
* Provides access to the Cluster API which can be used for managing cluster resources in Rancher UI
6+
*
7+
* @example
8+
* ```ts
9+
* import { useResources, K8S } from '@shell/apis';
10+
*
11+
* // Cluster-scoped resources (current cluster context)
12+
* const pod = await resources.cluster.find(K8S.POD, 'default/my-pod-123');
13+
*
14+
* // Management/global resources
15+
* const user = await resources.mgmt.find(K8S.USER, 'u-xyz789');
16+
* ```
17+
*/
18+
export type ClusterApi = ResourcesApi
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { ResourcesApi } from './resources-api';
2+
3+
/**
4+
* @interface
5+
* Provides access to the Management layer in Rancher UI (users, global settings, etc.)
6+
*
7+
* @example
8+
* ```ts
9+
* import { useResources, K8S } from '@shell/apis';
10+
* const resources = useResources();
11+
*
12+
* const user = await resources.mgmt.find(K8S.USER, 'u-xyz789');
13+
* ```
14+
*/
15+
export type MgmtApi = ResourcesApi

0 commit comments

Comments
 (0)