-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: custom busola extensions #3523
Changes from 7 commits
20f3c84
7b42988
881b959
1c12253
ce0d50b
c73668f
ee5d4eb
7a52a13
d3a05e9
152dc7d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { request as httpsRequest } from 'https'; | ||
import { request as httpRequest } from 'http'; | ||
import { URL } from 'url'; | ||
|
||
async function proxyHandler(req, res) { | ||
const targetUrl = req.query.url; | ||
if (!targetUrl) { | ||
return res.status(400).send('Target URL is required as a query parameter'); | ||
} | ||
|
||
try { | ||
const parsedUrl = new URL(targetUrl); | ||
const isHttps = parsedUrl.protocol === 'https:'; | ||
const libRequest = isHttps ? httpsRequest : httpRequest; | ||
|
||
const options = { | ||
hostname: parsedUrl.hostname, | ||
port: parsedUrl.port || (isHttps ? 443 : 80), | ||
path: parsedUrl.pathname + parsedUrl.search, | ||
method: req.method, | ||
headers: { ...req.headers, host: parsedUrl.host }, | ||
}; | ||
|
||
const proxyReq = libRequest(options, proxyRes => { | ||
// Forward status and headers from the target response | ||
res.writeHead(proxyRes.statusCode, proxyRes.headers); | ||
// Pipe the response data from the target back to the client | ||
proxyRes.pipe(res); | ||
}); | ||
|
||
proxyReq.on('error', () => { | ||
res.status(500).send('An error occurred while making the proxy request.'); | ||
}); | ||
|
||
if (Buffer.isBuffer(req.body)) { | ||
proxyReq.end(req.body); // If the body is already buffered, use it directly. | ||
} else { | ||
req.pipe(proxyReq); // Otherwise, pipe the request for streamed or chunked data. | ||
} | ||
} catch (error) { | ||
res.status(500).send('An error occurred while processing the request.'); | ||
} | ||
} | ||
|
||
export { proxyHandler }; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,24 @@ | ||||||
# Custom Extensions | ||||||
|
||||||
Busola's custom extension feature allows you to design fully custom user interfaces that go beyond the built-in extensibility functionality. This feature is ideal for creating unique and specialized displays that are not covered by the built-in components. | ||||||
|
||||||
## Getting Started | ||||||
|
||||||
First, to enable the custom extension feature you need to set the corresponding feature flag in your busola config, which is disabled by default. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
```yaml | ||||||
EXTENSIBILITY_CUSTOM_COMPONENTS: | ||||||
isEnabled: true | ||||||
``` | ||||||
|
||||||
## Creating custom extensions | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Creating a custom extension is as straightforward as setting up a ConfigMap with the following sections: | ||||||
|
||||||
- `data.general`: Contains configuration details | ||||||
- `data.customHtml`: Defines static HTML content | ||||||
- `data.customScript`: Adds dynamic behavior to your extension. | ||||||
|
||||||
Once your ConfigMap is ready, add it to your cluster, and Busola will load and display your custom UI. | ||||||
|
||||||
The best way to get familiar with this mechanism is to have a look at our [example](./../../examples/custom-extension/README.md), where everything is explained in detail. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -56,6 +56,15 @@ EXTENSIBILITY: | |||||
isEnabled: true | ||||||
``` | ||||||
|
||||||
- **EXTENSIBILITY_CUSTOM_COMPONENTS** - is used to indicate whether entirely custom extensions can be added to Busola. An example for a custom extension can be found [here](../examples/custom-extension/README.md). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Default settings: | ||||||
|
||||||
```yaml | ||||||
EXTENSIBILITY_CUSTOM_COMPONENTS: | ||||||
isEnabled: false | ||||||
``` | ||||||
|
||||||
- **EXTERNAL_NODES** - a list of links to external websites. `category`: a category name, `icon`: an optional icon, `scope`: either `namespace` or `cluster` (defaults to `cluster`), `children`: a list of pairs (label and link). | ||||||
|
||||||
Default settings: | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,47 @@ | ||||||||
# Set Up Your Custom Busola Extension | ||||||||
|
||||||||
This example contains a basic custom extension, that queries all deployments of a selected namespace of your cluster, and additionally retrieves the current weather data for Munich, Germany from an external weather API. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
To set up and deploy your own custom Busola extension, follow these steps. | ||||||||
|
||||||||
### 1. Adjust Static HTML Content | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
Edit the `ui.html` file to define the static HTML content for your custom extension. | ||||||||
|
||||||||
--- | ||||||||
|
||||||||
### 2. Configure Dynamic Components | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
Set up dynamic or behavioral components by modifying the custom element defined in the `script.js` file. | ||||||||
|
||||||||
- **Accessing Kubernetes Resources**: Use the `fetchWrapper` function to interact with cluster resources through the Kubernetes API. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
- **Making External API Requests**: Use the `proxyFetch` function to handle requests to external APIs that are subject to CORS regulations. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
grego952 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
--- | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
### 3. Define Extension Metadata | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
Update the `general.yaml` file to define metadata for your custom extension. | ||||||||
|
||||||||
#### ⚠️ Important: | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
Ensure that the `general.customElement` property matches the name of the custom element defined in `script.js`. The script is loaded only once, and this property is used to determine whether the custom element is already defined. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
grego952 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
--- | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
### 4. Deploy Your Extension | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
Run `./deploy.sh` to create a ConfigMap and deploy it to your cluster | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To run this command, I need to have exported Kubeconfig to my cluster, please add this information, and also I'll consider changing the name of the sh file to some |
||||||||
|
||||||||
Alternatively, you can use the following command: | ||||||||
|
||||||||
```bash | ||||||||
kubectl kustomize . | kubectl apply -n kyma-system -f - | ||||||||
``` | ||||||||
|
||||||||
grego952 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
--- | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
### 5. Test Your Changes Locally | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
Run `npm start` to start the development server. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/bin/bash | ||
|
||
kubectl kustomize . > ./custom-ui.yaml | ||
kubectl apply -f ./custom-ui.yaml -n kyma-system |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
resource: | ||
kind: Secret | ||
version: v1 | ||
urlPath: custom-busola-extension-example | ||
category: Kyma | ||
name: Custom busola extension example | ||
scope: cluster | ||
customElement: my-custom-element | ||
description: >- | ||
Custom busola extension example |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
configMapGenerator: | ||
- name: custom-ui | ||
files: | ||
- customHtml=ui.html | ||
- customScript=script.js | ||
- general=general.yaml | ||
options: | ||
disableNameSuffixHash: true | ||
labels: | ||
busola.io/extension: 'resource' | ||
busola.io/extension-version: '0.5' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.