@jfvilas/plugin-kwirth-metrics 0.12.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +275 -0
- package/dist/api/KwirthMetricsClient.esm.js +74 -0
- package/dist/api/KwirthMetricsClient.esm.js.map +1 -0
- package/dist/api/types.esm.js +8 -0
- package/dist/api/types.esm.js.map +1 -0
- package/dist/assets/kwirthmetrics-component-not-found.svg +29 -0
- package/dist/assets/kwirthmetrics-logo.svg +15 -0
- package/dist/components/ClusterList/ClusterList.esm.js +30 -0
- package/dist/components/ClusterList/ClusterList.esm.js.map +1 -0
- package/dist/components/ComponentNotFound/ComponentNotFound.esm.js +60 -0
- package/dist/components/ComponentNotFound/ComponentNotFound.esm.js.map +1 -0
- package/dist/components/EntityKwirthMetricsContent/EntityKwirthMetricsContent.esm.js +526 -0
- package/dist/components/EntityKwirthMetricsContent/EntityKwirthMetricsContent.esm.js.map +1 -0
- package/dist/components/EntityKwirthMetricsContent/index.esm.js +2 -0
- package/dist/components/EntityKwirthMetricsContent/index.esm.js.map +1 -0
- package/dist/components/ObjectSelector/ObjectSelector.esm.js +82 -0
- package/dist/components/ObjectSelector/ObjectSelector.esm.js.map +1 -0
- package/dist/components/Options/Options.esm.js +28 -0
- package/dist/components/Options/Options.esm.js.map +1 -0
- package/dist/components/ShowError/ShowError.esm.js +20 -0
- package/dist/components/ShowError/ShowError.esm.js.map +1 -0
- package/dist/components/StatusLog/StatusLog.esm.js +10 -0
- package/dist/components/StatusLog/StatusLog.esm.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.esm.js +4 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/plugin.esm.js +33 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/routes.esm.js +8 -0
- package/dist/routes.esm.js.map +1 -0
- package/package.json +91 -0
package/README.md
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# KwirthMetrics Plugin
|
|
2
|
+
This package is a Backstage plugin for **showing real-time streamed Kubernetes objects' metrics** and perform **some basic pod operations** via [Kwirth](https://jfvilas.github.io/kwirth).
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## Version compatibility
|
|
6
|
+
This very first version of KwirthMetrics is compatible with Kwirth core server versions according to following table.
|
|
7
|
+
|
|
8
|
+
| Plugin Kwirth version | Kwirth version |
|
|
9
|
+
|-|-|
|
|
10
|
+
|0.0.1|0.4.20|
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## What for?
|
|
15
|
+
This Backstage plugin allows you viewing **Kubernetes metrics** in real time that are linked to your Backstage entities. It's very important to understand that for this plugin to work you need to install Kwirth on your Kubernetes cluster (aside from Kwirth Backstage backend plugin), that is, this plugin is just another frontend for [Kwirth](https://jfvilas.github.io/kwirth).
|
|
16
|
+
|
|
17
|
+
In this very first versoin of KwirthMetrics you will be able to perform at least this actions:
|
|
18
|
+
- Show real-time metrics of a source container (you can select which containers to view)
|
|
19
|
+
- Show real-time metrics of a source pod (including all its containers)
|
|
20
|
+
- Show real-time metrics of a set of pods (you can select what pods to chart)
|
|
21
|
+
- Restarting a kubernetes object (pod, set of pods or just a simple container). This capability is not designed to substitute your operation tools, it is just a way for your developers, for example, to self-solve restarting-pod needs without the complexity of giving them access to Lens, K9s, Headlamp or kubectl.
|
|
22
|
+
|
|
23
|
+
Kwirth is a really-easy-to-use data-exporting platform for Kubernetes that runs in only one pod (**no database is needed**). Refer to Kwirth GitHub project for [info on installation](https://github.com/jfvilas/kwirth?tab=readme-ov-file#installation). Kwirth installation is *one command away* from you!!.
|
|
24
|
+
|
|
25
|
+
In addition, you can access [Kwirth project here](https://github.com/jfvilas/kwirth).
|
|
26
|
+
|
|
27
|
+
## What is this plugin for?
|
|
28
|
+
This Backstage plugin adds Backstage a feature for showing **real-time charts showing of metrics** about your Kubernetes objects and its **resource consumption**.You can show this charts *directly inside your Backstage frontend* application. The plugin will be enabled for any entity that is correctly tagged (according to Backstage Kubernetes core feature) and its correpsonding Kubernetes resources are found on any of the clusters that have been added to Backstage.
|
|
29
|
+
|
|
30
|
+
In addition, Backstage users can **restart pods** if they are allowed to (according to KwirthMetrics and KwirthOps permissions).
|
|
31
|
+
|
|
32
|
+
When KwirthMetrics is correctly installed and configured, it is possible to stream and chart real-time Kubernetes metrics to your Backstage like in this sample we show here:
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
This frontend plugin **includes just the visualization of metrics** charts. All needed configuration, and specially all **permission settings** are done in the backend plugin and the app-config YAML. You can restrict access to pods, namespaces, clusters, etc. by configuring permissions to be applied by the backend plugin.
|
|
37
|
+
|
|
38
|
+
The ability to restart pods is also configured in the app-config (YAML, env or whatever), and **restartig permissions are set independently than chart streaming permissions**.
|
|
39
|
+
The backend plugin is the only responsible for configuration and permissionism, all the capabilities related with showing charts are implemented in the frontend plugin, which is in charge of establishing the connections to the corresponding Kwirth instances (running inside your Kubernetes clusters).
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## How does it work?
|
|
43
|
+
Let's explain this by following a user working sequence:
|
|
44
|
+
|
|
45
|
+
1. A Backstage user searchs for an entity in the Backstage.
|
|
46
|
+
2. In the entity page there will be a new tab named 'KWIRTHMETRICS'.
|
|
47
|
+
3. When the user clicks on KWIRTHMETRICS the frontend plugin sends a request to the backend plugin asking for metrics information on several Kubernetes clusters.
|
|
48
|
+
4. The backend plugin sends requests to the Kwirth instances that are running on all the clusters previously added to Backstage (via app-config YAML). These requests ask for the following: *'Tell me all the pods that are labeled with a specific kubernetes-id label and do correspond with the entity I'm looking for'*. In response to this query, each Kwirth instance answers with a list of pods and the namespaces where they are running.
|
|
49
|
+
5. The backend plugin checks the permissions of the connected user and prunes the pods list removing the ones that the user has not access to.
|
|
50
|
+
6. With the final pod list, the backend plugin sends requests to the Kwirth instances on the clusters asking for specific API Keys for streaming metrics and/or restarting Kubernetes objects.
|
|
51
|
+
7. The backend plugin then asks for a metrics list, that is, a list of the metrics the Kubernetes cluster can offer (the ones managed by the kubelet)
|
|
52
|
+
8. With all this information, the backend builds a unique response containing all the pods the user have access to, all the API keys needed to access (wherever it be streaming metrics information for charting or pod-restarting) those pods, and all the metrics available at each cluster.
|
|
53
|
+
|
|
54
|
+
If everyting is correctly configured and tagged, the user should see a list of clusters similar to the one we show bellow. When selecting a cluster, the user should see a list of namespaces where the entity is running and is elligible for showing metrics charts.
|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
1. Install corresponding Backstage backend plugin [more information here](https://www.npmjs.com/package/@jfvilas/plugin-kwirth-backend). The backend plugin of Kwirth is **shared with all front end plugins**, so you only need to install backend plugin once.
|
|
61
|
+
|
|
62
|
+
2. Install this KwirthMetrics Backstage frontend plugin:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# From your Backstage root directory
|
|
66
|
+
yarn --cwd packages/app add @jfvilas/plugin-kwirth-metrics @jfvilas/plugin-kwirth-common
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
3. Make sure the [Kwirth backend plugin](https://www.npmjs.com/package/@jfvilas/plugin-kwirth-backend#configure) is installed and configured.
|
|
70
|
+
|
|
71
|
+
4. Restart your Backstage instance.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
## Configuration: Entity Pages
|
|
75
|
+
1. Add the KwirthMetrics plugin as a tab in your Entity pages:
|
|
76
|
+
|
|
77
|
+
Firstly, import the plugin module.
|
|
78
|
+
```typescript
|
|
79
|
+
// In packages/app/src/components/catalog/EntityPage.tsx
|
|
80
|
+
import { EntityKwirthMetricsContent, isKwirthAvailable } from '@jfvilas/plugin-kwirth-common';
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Then, add a tab to your EntityPage (the 'if' is optional, you can keep the 'KwirthMetrics' tab always visible if you prefer to do it that way).
|
|
84
|
+
````jsx
|
|
85
|
+
// Note: Add to any other Pages as well (e.g. defaultEntityPage or webSiteEntityPage, for example)
|
|
86
|
+
const serviceEntityPage = (
|
|
87
|
+
<EntityLayout>
|
|
88
|
+
{/* other tabs... */}
|
|
89
|
+
<EntityLayout.Route if={isKwirthAvailable} path="/kwirthmetrics" title="KwirthMetrics">
|
|
90
|
+
<EntityKwirthMetricsContent />
|
|
91
|
+
</EntityLayout.Route>
|
|
92
|
+
</EntityLayout>
|
|
93
|
+
)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
2. Add `backstage.io/kubernetes-id` annotation to your `catalog-info.yaml` for the entities deployed to Kubernetes whose metrics you want to stream. This is the same annotation that the Kubernetes core plugin uses, so, maybe you already have added it to your components. It is also the same annotation other Kwirth plugins use.
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
metadata:
|
|
100
|
+
annotations:
|
|
101
|
+
backstage.io/kubernetes-id: entity-name
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
3. Add proper **labels** to your Kubernetes objects so Backstage can *link* **forward and backward** the Backstage entities with the Kubernetes objects. To do this, you need to add `labels` to your Kubernetes YAML objects (please, don't get confused: **annotations in Backstage YAML, labels in Kubernetes YAML**). This is an example of a typical Kubernetes deployment with the required label:
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
apiVersion: apps/v1
|
|
108
|
+
kind: Deployment
|
|
109
|
+
metadata:
|
|
110
|
+
name: ijkl
|
|
111
|
+
labels:
|
|
112
|
+
backstage.io/kubernetes-id: ijkl
|
|
113
|
+
spec:
|
|
114
|
+
selector:
|
|
115
|
+
matchLabels:
|
|
116
|
+
app: ijkl
|
|
117
|
+
template:
|
|
118
|
+
metadata:
|
|
119
|
+
name: 'ijkl-pod'
|
|
120
|
+
labels:
|
|
121
|
+
app: ijkl
|
|
122
|
+
backstage.io/kubernetes-id: ijkl
|
|
123
|
+
spec:
|
|
124
|
+
containers:
|
|
125
|
+
- name: ijkl
|
|
126
|
+
image: your-OCI-image
|
|
127
|
+
...
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Please note that the kubernetes-id label is **on the deployment** and on the **spec pod template** also.
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
## Ready, set, go!
|
|
134
|
+
If you performed all these steps you would see a 'KwirthMetrics' tab in your **Entity Page**, like this one:
|
|
135
|
+
|
|
136
|
+

|
|
137
|
+
|
|
138
|
+
When you access the tab, if you have not yet tagged your entities you would see a message like this one explaning how to do that:
|
|
139
|
+
|
|
140
|
+

|
|
141
|
+
|
|
142
|
+
Once you tag your entities and your Kubernetes objects, you should see something similar to this:
|
|
143
|
+
|
|
144
|
+

|
|
145
|
+
|
|
146
|
+
KwirthMetrics is ready to show your favourite charts!!
|
|
147
|
+
|
|
148
|
+
Just *select the cluster* on the cluster card and eventually set the *options* you want for the charts (we will explain them later). On the new card that will appear on right, you will see all the Kubernetes namespaces available and a control section (restart, play, pause and stop). *Select a namespace*, *click PLAY* button and your charts will start to show **in real-time**.
|
|
149
|
+
|
|
150
|
+

|
|
151
|
+
|
|
152
|
+
Feel free to open issues and ask for more features.
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
## Status information
|
|
156
|
+
When the metrics stream starts, and all along the life of the stream (until it gets stopped or the window is closed), you will receive status information regarding the pods and containers you are watching. This status information is shown on the top of the card (just at the immediate right of the cluster name) including 3 kinds of information:
|
|
157
|
+
|
|
158
|
+
- Info. Information regarding pod management at Kubernetes cluster level (new pod, pod ended or pod modified).
|
|
159
|
+
- Warning. Warnings related to the metrics stream.
|
|
160
|
+
- Error. If there is an error in the stream, like invalid key use, or erroneous pod tagging, errors will be shown here.
|
|
161
|
+
|
|
162
|
+
The icons will light up in its corresponding color when a new event takes place.
|
|
163
|
+
|
|
164
|
+
This is how it feels:
|
|
165
|
+
|
|
166
|
+

|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
## Restarting pods
|
|
170
|
+
If your Backstage administrator has configured **Restarting** permissions and you are permitted, you would see a "Restart Pod" button just on the left of the "Play" button.
|
|
171
|
+
|
|
172
|
+

|
|
173
|
+
|
|
174
|
+
When you are not allowed to restart a pod, you can see the icon but you cannot click it. Conversely, if you are allowed, you can click the button and the pod (in the *namespace you have selected*) will be restarted.
|
|
175
|
+
|
|
176
|
+
Please take into account that you may be allowed in one namespace but not in another one, or you may be allowed to restart pods on a cluster but not on another one. The restart icon will be enabled or disabled according to your pod, namespace and cluster permissions.
|
|
177
|
+
|
|
178
|
+
Please rememebr, "Pod restarting" is an optional feature that must be configured in two different points:
|
|
179
|
+
- At the app-config YAML, enabling/disabling the feature and adding restrictions (pod, namespace, cluster...)
|
|
180
|
+
- At the EntityPage, adding a property to KwithMetrics component that enables or disables restarting. If restarting is disabled on front component, the restarting icon will not appear.
|
|
181
|
+
|
|
182
|
+
Let's see an example.
|
|
183
|
+
|
|
184
|
+
### Enable restaring on Backstage front
|
|
185
|
+
You must edit the EntityPage page and modify your EntityKwirthMetricsContent for adding the "enableRestart" property as shown in following example:
|
|
186
|
+
|
|
187
|
+
```jsx
|
|
188
|
+
// Note: Add to any other Pages as well (e.g. defaultEntityPage or webSiteEntityPage, for example)
|
|
189
|
+
const serviceEntityPage = (
|
|
190
|
+
<EntityLayout>
|
|
191
|
+
|
|
192
|
+
{/* other tabs... */}
|
|
193
|
+
|
|
194
|
+
<EntityLayout.Route if={isKwirthAvailable} path="/kwirthmetrics" title="KwirthMetrics">
|
|
195
|
+
<EntityKwirthMetricsContent enableRestart={true}/>
|
|
196
|
+
</EntityLayout.Route>
|
|
197
|
+
</EntityLayout>
|
|
198
|
+
)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Enable restart on Backend
|
|
202
|
+
Restarting capabilities are always present in Backstage Kwirth Backend plugin, but they must be enabled (and permsssioned if needed) by tailoring your app-config file. Object restarting permissions works exactly the same as metrics-streaming or log-viewing permissions (namespace permission, pod permissions, and a set of allow/deny/except/unless rules). The only difference is the specific part of the app-config where restarting permissions must be set.
|
|
203
|
+
|
|
204
|
+
The following example shows a simple sample containing:
|
|
205
|
+
- Metrics streaming permissions for charting in all namespaces for all users.
|
|
206
|
+
- Pod restarting permissions enabled only for admins in 'production' namespace.
|
|
207
|
+
|
|
208
|
+
```yaml
|
|
209
|
+
kubernetes:
|
|
210
|
+
serviceLocatorMethod:
|
|
211
|
+
type: 'multiTenant'
|
|
212
|
+
clusterLocatorMethods:
|
|
213
|
+
- type: 'config'
|
|
214
|
+
clusters:
|
|
215
|
+
- name: Customer D (Kwirth Local)
|
|
216
|
+
title: 'k3s'
|
|
217
|
+
url: https://host.docker.internal:64506
|
|
218
|
+
kwirthHome: http://localhost/kwirth
|
|
219
|
+
kwirthApiKey: '144892e3-aa8d-4b15-a5ab-fd3789721ebe|permanent|cluster::::'
|
|
220
|
+
kwirthmetrics:
|
|
221
|
+
namespacePermissions:
|
|
222
|
+
podPermissions:
|
|
223
|
+
kwirthops:
|
|
224
|
+
namespacePermissions:
|
|
225
|
+
- production: ['group:default/administrators']
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
As you can see:
|
|
229
|
+
- There are no namespace nor pod restrictions for streaming metrics data ('kwirthmetrics' section)
|
|
230
|
+
- Operations permissions ('ops' channel, 'kwirthops' section) is restricted to group 'administrators' fro namespace 'production', and is free for the rest of users and goups.
|
|
231
|
+
|
|
232
|
+
## Chart options
|
|
233
|
+
The charting system implemented in KwirthMetrics has some configuration options whose meaning is explained below.
|
|
234
|
+
|
|
235
|
+
### Width
|
|
236
|
+
Set the number of charts you want to be shown on each line. If you have selected more than one asset (pod, container...), each asset will start showing charts on a new line, so KwirthMetrics will adjust each asset's charts to end on a whole line. For example, let's suppose you select 2 pods and select 4 metrics for each pod:
|
|
237
|
+
|
|
238
|
+
- If you set width to 4, you will see two lines, each line containing 4 charts (one for each metric), each line showing charts for each pod.
|
|
239
|
+
- If you set width to 3, you will see 4 lines:
|
|
240
|
+
- First line will contain first 3 metrics of first pod.
|
|
241
|
+
- Second line will show the last metric of firt pod.
|
|
242
|
+
- Third line will contain first 3 metrics of second pod.
|
|
243
|
+
- Fourth line will contain last metric of second pod.
|
|
244
|
+
- If you set width to a number larger than the number of selected metrics it will have no impact: the number of charts per line will be the number of selected metrics.
|
|
245
|
+
|
|
246
|
+
### Interval
|
|
247
|
+
Number of seconds between samples. Take into account that this interval is not the real cluster metrics smple rate, which must be set inside Kwirth core for each cluster.
|
|
248
|
+
|
|
249
|
+
### Depth
|
|
250
|
+
Number of values to hold on screen.
|
|
251
|
+
|
|
252
|
+
### Chart
|
|
253
|
+
Select the cart type to use:
|
|
254
|
+
- Value chart, shows a number with the last read value.
|
|
255
|
+
- Line chart, shows a line chart with 'depth' values.
|
|
256
|
+
- Area chart, shows an area chart with 'depth' values.
|
|
257
|
+
- Bar chart, shows a bar chart chart with 'depth' values.
|
|
258
|
+
|
|
259
|
+
### Aggregate / Merge / Stack
|
|
260
|
+
When you select more than one asset, **and the chart type is set to Bar or Area**, you can decide how to manage metrics that come from different sources:
|
|
261
|
+
|
|
262
|
+
- **Aggregte**, values of different sources will be added up, no matter the chart type you've selected.
|
|
263
|
+
- **Merge**, values of differnte sources (same metric but different source object) will be shonw in the same chart.
|
|
264
|
+
- **Stack**, if you've selected 'merge', you can decide to show stacked original values, or just show a sum of all the values on each sample.
|
|
265
|
+
|
|
266
|
+
Please check the examples below to understand how each one of these will behave:
|
|
267
|
+
|
|
268
|
+
**Aggregate**
|
|
269
|
+

|
|
270
|
+
|
|
271
|
+
**Merge**
|
|
272
|
+

|
|
273
|
+
|
|
274
|
+
**MErge and Stack**
|
|
275
|
+

|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { getVersion, requestAccess } from '@jfvilas/plugin-kwirth-common';
|
|
2
|
+
|
|
3
|
+
class KwirthMetricsClient {
|
|
4
|
+
discoveryApi;
|
|
5
|
+
fetchApi;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.discoveryApi = options.discoveryApi;
|
|
8
|
+
this.fetchApi = options.fetchApi;
|
|
9
|
+
}
|
|
10
|
+
// +++ test
|
|
11
|
+
async getVersion() {
|
|
12
|
+
return getVersion(this.discoveryApi, this.fetchApi);
|
|
13
|
+
}
|
|
14
|
+
// move to common
|
|
15
|
+
// async getVersion(): Promise<string> {
|
|
16
|
+
// try {
|
|
17
|
+
// const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')
|
|
18
|
+
// const targetUrl = `${baseUrl}/version`
|
|
19
|
+
// const result = await this.fetchApi.fetch(targetUrl)
|
|
20
|
+
// const data = await result.json()
|
|
21
|
+
// if (!result.ok) {
|
|
22
|
+
// throw new Error(`getVersion error: not ok`)
|
|
23
|
+
// }
|
|
24
|
+
// return data.version
|
|
25
|
+
// }
|
|
26
|
+
// catch (err) {
|
|
27
|
+
// throw new Error(`getVersion error: ${err}`)
|
|
28
|
+
// }
|
|
29
|
+
// }
|
|
30
|
+
async getResources(entity) {
|
|
31
|
+
try {
|
|
32
|
+
const baseUrl = await this.discoveryApi.getBaseUrl("kwirth");
|
|
33
|
+
const targetUrl = `${baseUrl}/start`;
|
|
34
|
+
var payload = JSON.stringify(entity);
|
|
35
|
+
const result = await this.fetchApi.fetch(targetUrl, { method: "POST", body: payload, headers: { "Content-Type": "application/json" } });
|
|
36
|
+
const data = await result.json();
|
|
37
|
+
if (!result.ok) {
|
|
38
|
+
throw new Error(`getResources error: not ok`);
|
|
39
|
+
}
|
|
40
|
+
return data;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
throw new Error(`getResources error: ${err}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async requestAccess(entity, channel, scopes) {
|
|
46
|
+
return requestAccess(this.discoveryApi, this.fetchApi, entity, channel, scopes);
|
|
47
|
+
}
|
|
48
|
+
//+++ move to backstage-common
|
|
49
|
+
// async requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]> {
|
|
50
|
+
// try {
|
|
51
|
+
// const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')
|
|
52
|
+
// var targetUrl:URL= new URL (`${baseUrl}/access`)
|
|
53
|
+
// targetUrl.searchParams.append('scopes',scopes.join(','))
|
|
54
|
+
// targetUrl.searchParams.append('channel',channel)
|
|
55
|
+
// var payload=JSON.stringify(entity)
|
|
56
|
+
// const result = await this.fetchApi.fetch(targetUrl, {method:'POST', body:payload, headers:{'Content-Type':'application/json'}})
|
|
57
|
+
// const data = await result.json() as ClusterValidPods[]
|
|
58
|
+
// // we reconstruct the 'Map' from string of arrays
|
|
59
|
+
// for (var c of data) {
|
|
60
|
+
// c.accessKeys = new Map(JSON.parse(((c as any).accessKeys)))
|
|
61
|
+
// }
|
|
62
|
+
// if (!result.ok) {
|
|
63
|
+
// throw new Error(`requestAccess error: not ok`)
|
|
64
|
+
// }
|
|
65
|
+
// return data
|
|
66
|
+
// }
|
|
67
|
+
// catch (err) {
|
|
68
|
+
// throw new Error(`requestAccess error: ${err}`)
|
|
69
|
+
// }
|
|
70
|
+
// }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { KwirthMetricsClient };
|
|
74
|
+
//# sourceMappingURL=KwirthMetricsClient.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KwirthMetricsClient.esm.js","sources":["../../src/api/KwirthMetricsClient.ts"],"sourcesContent":["/*\r\nCopyright 2024 Julio Fernandez\r\n\r\nLicensed under the Apache License, Version 2.0 (the \"License\");\r\nyou may not use this file except in compliance with the License.\r\nYou may obtain a copy of the License at\r\n\r\n http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nUnless required by applicable law or agreed to in writing, software\r\ndistributed under the License is distributed on an \"AS IS\" BASIS,\r\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nSee the License for the specific language governing permissions and\r\nlimitations under the License.\r\n*/\r\nimport { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api'\r\nimport { KwirthMetricsApi } from './types'\r\nimport { Entity } from '@backstage/catalog-model'\r\nimport { ClusterValidPods, getVersion, requestAccess } from '@jfvilas/plugin-kwirth-common'\r\nimport { InstanceConfigScopeEnum } from '@jfvilas/kwirth-common'\r\n\r\nexport interface KwirthMetricsClientOptions {\r\n discoveryApi: DiscoveryApi\r\n fetchApi: FetchApi\r\n}\r\n\r\nexport class KwirthMetricsClient implements KwirthMetricsApi {\r\n private readonly discoveryApi: DiscoveryApi\r\n private readonly fetchApi: FetchApi\r\n\r\n\r\n constructor(options: KwirthMetricsClientOptions) {\r\n this.discoveryApi = options.discoveryApi\r\n this.fetchApi = options.fetchApi\r\n }\r\n\r\n // +++ test\r\n async getVersion() : Promise<string> {\r\n return getVersion(this.discoveryApi, this.fetchApi)\r\n }\r\n\r\n // move to common\r\n // async getVersion(): Promise<string> {\r\n // try {\r\n // const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')\r\n // const targetUrl = `${baseUrl}/version`\r\n\r\n // const result = await this.fetchApi.fetch(targetUrl)\r\n // const data = await result.json()\r\n\r\n // if (!result.ok) {\r\n // throw new Error(`getVersion error: not ok`)\r\n // }\r\n // return data.version\r\n // }\r\n // catch (err) {\r\n // throw new Error(`getVersion error: ${err}`)\r\n // }\r\n // }\r\n\r\n async getResources(entity:Entity): Promise<ClusterValidPods> {\r\n try {\r\n const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')\r\n const targetUrl = `${baseUrl}/start`\r\n\r\n var payload=JSON.stringify(entity)\r\n const result = await this.fetchApi.fetch(targetUrl, {method:'POST', body:payload, headers:{'Content-Type':'application/json'}})\r\n const data = await result.json() as ClusterValidPods\r\n\r\n if (!result.ok) {\r\n throw new Error(`getResources error: not ok`)\r\n }\r\n return data\r\n }\r\n catch (err) {\r\n throw new Error(`getResources error: ${err}`)\r\n }\r\n }\r\n\r\n async requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]> {\r\n return requestAccess(this.discoveryApi, this.fetchApi, entity, channel, scopes)\r\n }\r\n\r\n //+++ move to backstage-common\r\n // async requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]> {\r\n // try {\r\n // const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')\r\n // var targetUrl:URL= new URL (`${baseUrl}/access`)\r\n // targetUrl.searchParams.append('scopes',scopes.join(','))\r\n // targetUrl.searchParams.append('channel',channel)\r\n\r\n // var payload=JSON.stringify(entity)\r\n // const result = await this.fetchApi.fetch(targetUrl, {method:'POST', body:payload, headers:{'Content-Type':'application/json'}})\r\n // const data = await result.json() as ClusterValidPods[]\r\n\r\n // // we reconstruct the 'Map' from string of arrays\r\n // for (var c of data) {\r\n // c.accessKeys = new Map(JSON.parse(((c as any).accessKeys)))\r\n // }\r\n // if (!result.ok) {\r\n // throw new Error(`requestAccess error: not ok`)\r\n // }\r\n // return data\r\n // }\r\n // catch (err) {\r\n // throw new Error(`requestAccess error: ${err}`)\r\n // }\r\n // }\r\n\r\n}\r\n"],"names":[],"mappings":";;AA0BO,MAAM,mBAAgD,CAAA;AAAA,EACxC,YAAA;AAAA,EACA,QAAA;AAAA,EAGjB,YAAY,OAAqC,EAAA;AAC7C,IAAA,IAAA,CAAK,eAAe,OAAQ,CAAA,YAAA;AAC5B,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA;AAAA;AAC5B;AAAA,EAGA,MAAM,UAA+B,GAAA;AACjC,IAAA,OAAO,UAAW,CAAA,IAAA,CAAK,YAAc,EAAA,IAAA,CAAK,QAAQ,CAAA;AAAA;AACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,MAAM,aAAa,MAA0C,EAAA;AACzD,IAAI,IAAA;AACA,MAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,QAAQ,CAAA;AAC3D,MAAM,MAAA,SAAA,GAAY,GAAG,OAAO,CAAA,MAAA,CAAA;AAE5B,MAAI,IAAA,OAAA,GAAQ,IAAK,CAAA,SAAA,CAAU,MAAM,CAAA;AACjC,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,QAAS,CAAA,KAAA,CAAM,WAAW,EAAC,MAAA,EAAO,MAAQ,EAAA,IAAA,EAAK,SAAS,OAAQ,EAAA,EAAC,cAAe,EAAA,kBAAA,IAAoB,CAAA;AAC9H,MAAM,MAAA,IAAA,GAAO,MAAM,MAAA,CAAO,IAAK,EAAA;AAE/B,MAAI,IAAA,CAAC,OAAO,EAAI,EAAA;AACZ,QAAM,MAAA,IAAI,MAAM,CAA4B,0BAAA,CAAA,CAAA;AAAA;AAEhD,MAAO,OAAA,IAAA;AAAA,aAEJ,GAAK,EAAA;AACR,MAAA,MAAM,IAAI,KAAA,CAAM,CAAuB,oBAAA,EAAA,GAAG,CAAE,CAAA,CAAA;AAAA;AAChD;AACJ,EAEA,MAAM,aAAA,CAAc,MAAe,EAAA,OAAA,EAAgB,MAA+D,EAAA;AAC9G,IAAA,OAAO,cAAc,IAAK,CAAA,YAAA,EAAc,KAAK,QAAU,EAAA,MAAA,EAAQ,SAAS,MAAM,CAAA;AAAA;AAClF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BJ;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.esm.js","sources":["../../src/api/types.ts"],"sourcesContent":["/*\r\nCopyright 2024 Julio Fernandez\r\n\r\nLicensed under the Apache License, Version 2.0 (the \"License\");\r\nyou may not use this file except in compliance with the License.\r\nYou may obtain a copy of the License at\r\n\r\n http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nUnless required by applicable law or agreed to in writing, software\r\ndistributed under the License is distributed on an \"AS IS\" BASIS,\r\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nSee the License for the specific language governing permissions and\r\nlimitations under the License.\r\n*/\r\nimport { Entity } from '@backstage/catalog-model'\r\nimport { createApiRef } from '@backstage/core-plugin-api'\r\nimport { InstanceConfigScopeEnum } from '@jfvilas/kwirth-common'\r\nimport { ClusterValidPods } from '@jfvilas/plugin-kwirth-common'\r\n\r\nexport interface KwirthMetricsApi {\r\n requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]>\r\n getResources(entity:Entity): Promise<ClusterValidPods>\r\n getVersion(): Promise<string>\r\n}\r\n\r\nexport const kwirthMetricsApiRef = createApiRef<KwirthMetricsApi>({\r\n id: 'plugin.kwirthmetrics.api',\r\n})\r\n"],"names":[],"mappings":";;AA0BO,MAAM,sBAAsB,YAA+B,CAAA;AAAA,EAChE,EAAI,EAAA;AACN,CAAC;;;;"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<svg viewBox="0 0 340 260" width="340px" height="260px" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
|
|
2
|
+
<defs>
|
|
3
|
+
<bx:export>
|
|
4
|
+
<bx:file format="svg"></bx:file>
|
|
5
|
+
</bx:export>
|
|
6
|
+
</defs>
|
|
7
|
+
<g transform="matrix(0.9912869334220885, 0, 0, 0.9992620348930358, -14.405802726745609, -13.716870307922363)">
|
|
8
|
+
<rect style="fill-rule: nonzero; stroke: rgb(255, 255, 255); stroke-width: 0px; fill: rgb(230, 230, 230); transform-origin: 251.826px 205.425px;" transform="matrix(0.985986, -0.166827, 0.164416, 0.986394, -63.927027, -123.853593)" x="111.287" y="192.512" width="281.077" height="25.826" rx="12.015" ry="12.015"></rect>
|
|
9
|
+
<rect style="fill-rule: nonzero; stroke: rgb(255, 255, 255); stroke-width: 0px; fill: rgb(230, 230, 230); transform-origin: 183.734px 205.425px;" transform="matrix(0.985986, -0.166827, 0.164416, 0.986394, 25.09495, -102.378974)" x="81.196" y="192.512" width="205.077" height="25.826" rx="12.015" ry="12.015"></rect>
|
|
10
|
+
<rect style="fill-rule: nonzero; stroke: rgb(255, 255, 255); stroke-width: 0px; fill: rgb(230, 230, 230); transform-origin: 233.847px 205.425px;" transform="matrix(0.985986, -0.166827, 0.164416, 0.986394, -88.514386, -142.044601)" x="103.341" y="192.512" width="261.01" height="25.826" rx="12.015" ry="12.015"></rect>
|
|
11
|
+
<rect style="fill-rule: nonzero; stroke: rgb(255, 255, 255); stroke-width: 0px; fill: rgb(230, 230, 230); transform-origin: 293.722px 205.425px;" transform="matrix(0.985986, -0.166827, 0.164416, 0.986394, -99.946111, -14.149463)" x="129.802" y="192.512" width="327.839" height="25.826" rx="12.015" ry="12.015"></rect>
|
|
12
|
+
<rect style="fill-rule: nonzero; stroke: rgb(255, 255, 255); stroke-width: 0px; fill: rgb(230, 230, 230); transform-origin: 230.511px 205.425px;" transform="matrix(0.985986, -0.166827, 0.164416, 0.986394, -36.575721, 10.839559)" x="101.867" y="192.512" width="257.287" height="25.826" rx="12.015" ry="12.015"></rect>
|
|
13
|
+
<rect style="fill-rule: nonzero; stroke: rgb(255, 255, 255); stroke-width: 0px; fill: rgb(230, 230, 230); transform-origin: 233.847px 205.425px;" transform="matrix(0.985986, -0.166827, 0.164416, 0.986394, -59.583989, -36.241093)" x="103.341" y="192.512" width="261.01" height="25.826" rx="12.015" ry="12.015"></rect>
|
|
14
|
+
</g>
|
|
15
|
+
<defs id="defs2713"></defs>
|
|
16
|
+
<path style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; font-size: medium; line-height: normal; font-family: sans-serif; font-feature-settings: normal; text-indent: 0px; text-align: start; text-decoration: none solid rgb(0, 0, 0); letter-spacing: normal; word-spacing: normal; text-transform: none; writing-mode: lr-tb; direction: ltr; text-orientation: mixed; dominant-baseline: auto; baseline-shift: baseline; text-anchor: start; white-space: normal; clip-rule: nonzero; display: inline; overflow: visible; visibility: visible; opacity: 1; isolation: auto; mix-blend-mode: normal; color-interpolation: srgb; color-interpolation-filters: linearrgb; vector-effect: none; fill: rgb(255, 255, 255); fill-opacity: 1; fill-rule: evenodd; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0; stroke-opacity: 1; color-rendering: auto; image-rendering: auto; shape-rendering: auto; text-rendering: auto; paint-order: fill; stroke-width: 9px; stroke: rgb(74, 74, 74);" d="M 88.657 30.45 L 234.73 30.45 L 234.73 224.269 L 88.657 224.269 L 88.657 30.45 Z" id="path3310"></path>
|
|
17
|
+
<g id="g3330" transform="matrix(0.441208, 0, 0, 0.468544, -801.855, -5194.43)">
|
|
18
|
+
<path id="path3312" d="m 2063.75,11395.242 h 238.125" style="fill: none; fill-rule: evenodd; stroke-width: 23.8125; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 0.870588; paint-order: fill; stroke: rgb(167, 171, 176);"></path>
|
|
19
|
+
<path id="path3316" d="m 2063.75,11501.075 h 238.125" style="fill: none; fill-rule: evenodd; stroke-width: 23.8125; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 0.870588; paint-order: fill; stroke: rgb(167, 171, 176);"></path>
|
|
20
|
+
<g transform="matrix(1.4118204,0,0,1.4118204,755.9522,3488.749)" id="g3328">
|
|
21
|
+
<path style="fill-opacity: 1; fill-rule: evenodd; stroke-width: 0.193224px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; paint-order: fill; fill: rgb(188, 187, 186); stroke: rgb(167, 171, 176);" d="m 978.95834,5562.2084 v -42.3334 h 26.45836 v 42.3334 z" id="path3318"></path>
|
|
22
|
+
<path id="path3320" d="m 1010.7083,5562.2084 v -52.9167 h 26.4584 v 52.9167 z" style="fill-opacity: 1; fill-rule: evenodd; stroke-width: 0.216031px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; paint-order: fill; fill: rgb(188, 187, 186); stroke: rgb(167, 171, 176);"></path>
|
|
23
|
+
<path style="fill-opacity: 1; fill-rule: evenodd; stroke-width: 0.236651px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; paint-order: fill; fill: rgb(188, 187, 186); stroke: rgb(167, 171, 176);" d="m 1042.4583,5562.2084 v -63.5 h 26.4584 v 63.5 z" id="path3322"></path>
|
|
24
|
+
<path id="path3324" d="m 947.20834,5562.2084 v -31.75 h 26.45836 v 31.75 z" style="fill-opacity: 1; fill-rule: evenodd; stroke-width: 0.167337px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; paint-order: fill; fill: rgb(188, 187, 186); stroke: rgb(167, 171, 176);"></path>
|
|
25
|
+
<path id="path3326" transform="scale(0.26458333)" d="m 4011.668,20662.062 a 7.8996132,7.8996132 0 0 0 -7.4668,10.43 l 5.0429,14.922 -432.4082,144.131 a 10.002756,10.002756 0 1 0 6.3262,18.978 l 432.4824,-144.162 4.9082,14.528 a 7.8996132,7.8996132 0 0 0 13.4141,2.689 l 16.8711,-19.182 16.8691,-19.179 a 7.8996132,7.8996132 0 0 0 -0.8945,-11.299 v 0 a 7.8996132,7.8996132 0 0 0 -0.6289,-0.477 7.8996132,7.8996132 0 0 0 -2.8554,-1.189 l -25.045,-5.02 -25.0449,-5.019 a 7.8996132,7.8996132 0 0 0 -1.5683,-0.155 z" style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; font-size: medium; line-height: normal; font-family: sans-serif; font-feature-settings: normal; text-indent: 0px; text-align: start; text-decoration: none solid rgb(0, 0, 0); letter-spacing: normal; word-spacing: normal; text-transform: none; writing-mode: lr-tb; direction: ltr; text-orientation: mixed; dominant-baseline: auto; baseline-shift: baseline; text-anchor: start; white-space: normal; clip-rule: nonzero; display: inline; overflow: visible; visibility: visible; opacity: 1; isolation: auto; mix-blend-mode: normal; color-interpolation: srgb; color-interpolation-filters: linearrgb; vector-effect: none; fill-opacity: 1; fill-rule: evenodd; stroke-width: 20; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0; stroke-opacity: 1; color-rendering: auto; image-rendering: auto; shape-rendering: auto; text-rendering: auto; paint-order: fill; stroke: rgb(167, 171, 176); fill: rgb(170, 169, 168);"></path>
|
|
26
|
+
</g>
|
|
27
|
+
</g>
|
|
28
|
+
<text style="fill: rgb(74, 74, 74); font-family: Consolas; font-size: 34px; font-weight: 700; stroke-miterlimit: 10; stroke-width: 0px; white-space: pre;" transform="matrix(0.474467, 0, 0, 0.44399, 48.3521, 109.292)" x="114.293" y="147.365">KwirthMetrics</text>
|
|
29
|
+
</svg>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<svg viewBox="0 0 152 200" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
|
|
2
|
+
<path style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; font-size: medium; line-height: normal; font-family: sans-serif; font-feature-settings: normal; text-indent: 0px; text-align: start; text-decoration: none solid rgb(0, 0, 0); letter-spacing: normal; word-spacing: normal; text-transform: none; writing-mode: lr-tb; direction: ltr; text-orientation: mixed; dominant-baseline: auto; baseline-shift: baseline; text-anchor: start; white-space: normal; clip-rule: nonzero; display: inline; overflow: visible; visibility: visible; opacity: 1; isolation: auto; mix-blend-mode: normal; color-interpolation: srgb; color-interpolation-filters: linearrgb; vector-effect: none; fill: rgb(255, 255, 255); fill-opacity: 1; fill-rule: evenodd; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0; stroke-opacity: 1; color-rendering: auto; image-rendering: auto; shape-rendering: auto; text-rendering: auto; paint-order: fill; stroke-width: 9px; stroke: rgb(74, 74, 74);" d="M 3.001 3.226 L 149.074 3.226 L 149.074 197.045 L 3.001 197.045 L 3.001 3.226 Z" id="path3310"></path>
|
|
3
|
+
<g id="g3330" transform="matrix(0.422907, 0, 0, 0.468544, -846.30304, -5221.649902)" style="">
|
|
4
|
+
<path id="path3312" d="m 2063.75,11395.242 h 238.125" style="fill: none; fill-rule: evenodd; stroke-width: 23.8125; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 0.870588; paint-order: fill; stroke: rgb(167, 171, 176);"></path>
|
|
5
|
+
<path id="path3316" d="m 2063.75,11501.075 h 238.125" style="fill: none; fill-rule: evenodd; stroke-width: 23.8125; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 0.870588; paint-order: fill; stroke: rgb(167, 171, 176);"></path>
|
|
6
|
+
<g transform="matrix(1.4118204,0,0,1.4118204,755.9522,3488.749)" id="g3328">
|
|
7
|
+
<path style="fill-opacity: 1; fill-rule: evenodd; stroke-width: 0.193224px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; paint-order: fill; fill: rgb(188, 187, 186); stroke: rgb(167, 171, 176);" d="m 978.95834,5562.2084 v -42.3334 h 26.45836 v 42.3334 z" id="path3318"></path>
|
|
8
|
+
<path id="path3320" d="m 1010.7083,5562.2084 v -52.9167 h 26.4584 v 52.9167 z" style="fill-opacity: 1; fill-rule: evenodd; stroke-width: 0.216031px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; paint-order: fill; fill: rgb(188, 187, 186); stroke: rgb(167, 171, 176);"></path>
|
|
9
|
+
<path style="fill-opacity: 1; fill-rule: evenodd; stroke-width: 0.236651px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; paint-order: fill; fill: rgb(188, 187, 186); stroke: rgb(167, 171, 176);" d="m 1042.4583,5562.2084 v -63.5 h 26.4584 v 63.5 z" id="path3322"></path>
|
|
10
|
+
<path id="path3324" d="m 947.20834,5562.2084 v -31.75 h 26.45836 v 31.75 z" style="fill-opacity: 1; fill-rule: evenodd; stroke-width: 0.167337px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; paint-order: fill; fill: rgb(188, 187, 186); stroke: rgb(167, 171, 176);"></path>
|
|
11
|
+
<path id="path3326" transform="scale(0.26458333)" d="m 4011.668,20662.062 a 7.8996132,7.8996132 0 0 0 -7.4668,10.43 l 5.0429,14.922 -432.4082,144.131 a 10.002756,10.002756 0 1 0 6.3262,18.978 l 432.4824,-144.162 4.9082,14.528 a 7.8996132,7.8996132 0 0 0 13.4141,2.689 l 16.8711,-19.182 16.8691,-19.179 a 7.8996132,7.8996132 0 0 0 -0.8945,-11.299 v 0 a 7.8996132,7.8996132 0 0 0 -0.6289,-0.477 7.8996132,7.8996132 0 0 0 -2.8554,-1.189 l -25.045,-5.02 -25.0449,-5.019 a 7.8996132,7.8996132 0 0 0 -1.5683,-0.155 z" style="color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; font-size: medium; line-height: normal; font-family: sans-serif; font-feature-settings: normal; text-indent: 0px; text-align: start; text-decoration: none solid rgb(0, 0, 0); letter-spacing: normal; word-spacing: normal; text-transform: none; writing-mode: lr-tb; direction: ltr; text-orientation: mixed; dominant-baseline: auto; baseline-shift: baseline; text-anchor: start; white-space: normal; clip-rule: nonzero; display: inline; overflow: visible; visibility: visible; opacity: 1; isolation: auto; mix-blend-mode: normal; color-interpolation: srgb; color-interpolation-filters: linearrgb; vector-effect: none; fill-opacity: 1; fill-rule: evenodd; stroke-width: 20; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0; stroke-opacity: 1; color-rendering: auto; image-rendering: auto; shape-rendering: auto; text-rendering: auto; paint-order: fill; stroke: rgb(167, 171, 176); fill: rgb(170, 169, 168);"></path>
|
|
12
|
+
</g>
|
|
13
|
+
</g>
|
|
14
|
+
<text style="fill: rgb(74, 74, 74); font-family: Consolas; font-size: 34px; font-weight: 700; stroke-miterlimit: 10; stroke-width: 0px; white-space: pre;" transform="matrix(0.452757, 0, 0, 0.44399, -30.425272, 82.343803)" x="114.293" y="147.365">KwirthMetrics</text>
|
|
15
|
+
</svg>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Box from '@material-ui/core/Box';
|
|
3
|
+
import CardHeader from '@material-ui/core/CardHeader';
|
|
4
|
+
import Divider from '@material-ui/core/Divider';
|
|
5
|
+
import List from '@material-ui/core/List';
|
|
6
|
+
import ListItem from '@material-ui/core/ListItem';
|
|
7
|
+
import ListItemText from '@material-ui/core/ListItemText';
|
|
8
|
+
import Typography from '@material-ui/core/Typography';
|
|
9
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
10
|
+
|
|
11
|
+
const useStyles = makeStyles((_theme) => ({
|
|
12
|
+
clusterBox: {
|
|
13
|
+
display: "flex",
|
|
14
|
+
marginTop: "8px"
|
|
15
|
+
}
|
|
16
|
+
}));
|
|
17
|
+
const ClusterList = (props) => {
|
|
18
|
+
const classes = useStyles();
|
|
19
|
+
const { resources, selectedClusterName, onSelect } = props;
|
|
20
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(CardHeader, { title: "Clusters" }), /* @__PURE__ */ React.createElement(Divider, { style: { marginTop: 8 } }), /* @__PURE__ */ React.createElement(List, { dense: true }, resources.map((cluster, index) => /* @__PURE__ */ React.createElement(ListItem, { button: true, key: index, selected: selectedClusterName === cluster.name, onClick: () => onSelect(cluster.name), disabled: cluster.data.length === 0 }, /* @__PURE__ */ React.createElement(
|
|
21
|
+
ListItemText,
|
|
22
|
+
{
|
|
23
|
+
primary: cluster.name,
|
|
24
|
+
secondary: /* @__PURE__ */ React.createElement(Box, { component: "span", className: classes.clusterBox }, /* @__PURE__ */ React.createElement(Typography, { component: "span", style: { fontSize: 12 } }, cluster.title))
|
|
25
|
+
}
|
|
26
|
+
)))));
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export { ClusterList };
|
|
30
|
+
//# sourceMappingURL=ClusterList.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClusterList.esm.js","sources":["../../../src/components/ClusterList/ClusterList.tsx"],"sourcesContent":["import React from 'react'\r\nimport Box from '@material-ui/core/Box'\r\nimport CardHeader from '@material-ui/core/CardHeader'\r\nimport Divider from '@material-ui/core/Divider'\r\nimport List from '@material-ui/core/List'\r\nimport ListItem from '@material-ui/core/ListItem'\r\nimport ListItemText from '@material-ui/core/ListItemText'\r\nimport Typography from '@material-ui/core/Typography'\r\nimport { makeStyles, Theme } from '@material-ui/core/styles'\r\nimport { ClusterValidPods } from '@jfvilas/plugin-kwirth-common'\r\n\r\nconst useStyles = makeStyles((_theme: Theme) => ({\r\n clusterBox: {\r\n display: 'flex',\r\n marginTop: '8px',\r\n },\r\n}));\r\n \r\nconst ClusterList = (props: {\r\n\t\tresources: ClusterValidPods[]\r\n\t\tselectedClusterName: string\r\n\t\tonSelect:(name:string|undefined) => void\r\n\t}) => {\r\n \r\n const classes=useStyles();\r\n const { resources, selectedClusterName, onSelect } = props;\r\n \r\n\treturn (\r\n\t\t<>\r\n\t\t<CardHeader title={'Clusters'}/>\r\n\t\t\r\n\t\t<Divider style={{marginTop:8}}/>\r\n\r\n\t\t<List dense>\r\n\t\t\t{resources.map((cluster, index) => (\r\n\t\t\t<ListItem button key={index} selected={selectedClusterName === cluster.name} onClick={() => onSelect(cluster.name)} disabled={cluster.data.length===0}>\r\n\t\t\t\t<ListItemText\r\n\t\t\t\tprimary={cluster.name}\r\n\t\t\t\tsecondary={\r\n\t\t\t\t\t<Box component={'span'} className={classes.clusterBox}>\r\n\t\t\t\t\t<Typography component={'span'} style={{fontSize:12}}>\r\n\t\t\t\t\t\t{cluster.title}\r\n\t\t\t\t\t</Typography>\r\n\t\t\t\t\t</Box>\r\n\t\t\t\t}\r\n\t\t\t\t/>\r\n\t\t\t</ListItem>\r\n\t\t\t))}\r\n\t\t</List>\r\n\t\t</>\r\n\t)\r\n}\r\n\r\nexport { ClusterList }"],"names":[],"mappings":";;;;;;;;;;AAWA,MAAM,SAAA,GAAY,UAAW,CAAA,CAAC,MAAmB,MAAA;AAAA,EAC7C,UAAY,EAAA;AAAA,IACV,OAAS,EAAA,MAAA;AAAA,IACT,SAAW,EAAA;AAAA;AAEjB,CAAE,CAAA,CAAA;AAEI,MAAA,WAAA,GAAc,CAAC,KAId,KAAA;AAEH,EAAA,MAAM,UAAQ,SAAU,EAAA;AACxB,EAAA,MAAM,EAAE,SAAA,EAAW,mBAAqB,EAAA,QAAA,EAAa,GAAA,KAAA;AAExD,EAAA,iFAEE,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAO,UAAW,EAAA,CAAA,sCAE7B,OAAQ,EAAA,EAAA,KAAA,EAAO,EAAC,SAAU,EAAA,CAAA,IAAG,CAE9B,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,KAAK,EAAA,IAAA,EAAA,EACT,UAAU,GAAI,CAAA,CAAC,SAAS,KACzB,qBAAA,KAAA,CAAA,aAAA,CAAC,YAAS,MAAM,EAAA,IAAA,EAAC,KAAK,KAAO,EAAA,QAAA,EAAU,wBAAwB,OAAQ,CAAA,IAAA,EAAM,SAAS,MAAM,QAAA,CAAS,QAAQ,IAAI,CAAA,EAAG,UAAU,OAAQ,CAAA,IAAA,CAAK,WAAS,CACnJ,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MACD,SAAS,OAAQ,CAAA,IAAA;AAAA,MACjB,2BACE,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,WAAW,MAAQ,EAAA,SAAA,EAAW,QAAQ,UAC3C,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,SAAW,EAAA,MAAA,EAAQ,OAAO,EAAC,QAAA,EAAS,IAC9C,EAAA,EAAA,OAAA,CAAQ,KACV,CACA;AAAA;AAAA,GAGF,CACC,CACF,CACA,CAAA;AAEF;;;;"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CodeSnippet } from '@backstage/core-components';
|
|
3
|
+
import { Grid, Typography, Button } from '@material-ui/core';
|
|
4
|
+
import KwirthComponentNotFound from '../../assets/kwirthmetrics-component-not-found.svg';
|
|
5
|
+
import { ANNOTATION_KWIRTH_LOCATION } from '@jfvilas/plugin-kwirth-common';
|
|
6
|
+
|
|
7
|
+
var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
|
|
8
|
+
ErrorType2[ErrorType2["NO_PODS"] = 0] = "NO_PODS";
|
|
9
|
+
ErrorType2[ErrorType2["NO_CLUSTERS"] = 1] = "NO_CLUSTERS";
|
|
10
|
+
return ErrorType2;
|
|
11
|
+
})(ErrorType || {});
|
|
12
|
+
const KUBERNETES_YAML = `apiVersion: apps/v1
|
|
13
|
+
kind: Deployment
|
|
14
|
+
metadata:
|
|
15
|
+
name: '$entityName'
|
|
16
|
+
description: '$entityDescription'
|
|
17
|
+
labels:
|
|
18
|
+
${ANNOTATION_KWIRTH_LOCATION} : '$entityName'
|
|
19
|
+
spec:
|
|
20
|
+
selector:
|
|
21
|
+
matchLabels:
|
|
22
|
+
app: '$entityName'
|
|
23
|
+
template:
|
|
24
|
+
metadata:
|
|
25
|
+
name: '$entityName'-pod
|
|
26
|
+
labels:
|
|
27
|
+
app: '$entityName'
|
|
28
|
+
${ANNOTATION_KWIRTH_LOCATION} : '$entityName'
|
|
29
|
+
spec:
|
|
30
|
+
containers:
|
|
31
|
+
- name: '$entityName'
|
|
32
|
+
image: your-OCI-image
|
|
33
|
+
...`;
|
|
34
|
+
const ComponentNotFound = (props) => {
|
|
35
|
+
var text = "";
|
|
36
|
+
var content = /* @__PURE__ */ React.createElement(
|
|
37
|
+
CodeSnippet,
|
|
38
|
+
{
|
|
39
|
+
text: KUBERNETES_YAML.replaceAll("$entityName", props.entity.metadata.name).replaceAll("$entityDescription", props.entity.metadata.description),
|
|
40
|
+
language: "yaml",
|
|
41
|
+
showLineNumbers: true,
|
|
42
|
+
highlightedNumbers: [7, 17],
|
|
43
|
+
customStyle: { background: "inherit" }
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
var nopodsMsg = `Although this component is well tagged, and we have found some clusters configured in Backstage, we were unable to find "${props.entity.metadata.name}" running on any pod. Maybe you need to tag Kubernetes objects (deployment and pod templates).`;
|
|
47
|
+
var noclustersMsg = `Although this component has a correct 'kubernetes-id' in the ${props.entity.metadata.name} Component YAML, we couldn't find any cluster. Maybe you need to tag Kubernetes objects (deployments and pod templates).`;
|
|
48
|
+
switch (props.error) {
|
|
49
|
+
case 0 /* NO_PODS */:
|
|
50
|
+
text = nopodsMsg;
|
|
51
|
+
break;
|
|
52
|
+
case 1 /* NO_CLUSTERS */:
|
|
53
|
+
text = noclustersMsg;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "row", justifyContent: "flex-start", alignItems: "flex-start", spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 6, md: 6 }, /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "column" }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, "Component not found")), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, text)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, content))), /* @__PURE__ */ React.createElement("img", { src: KwirthComponentNotFound, style: { left: "10%", marginTop: "10%", width: "30%", position: "relative" } })), /* @__PURE__ */ React.createElement(Button, { variant: "contained", color: "primary", target: "_blank", href: "https://backstage.io/docs/features/kubernetes/configuration#surfacing-your-kubernetes-components-as-part-of-an-entity" }, "READ MORE"));
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export { ComponentNotFound, ErrorType };
|
|
60
|
+
//# sourceMappingURL=ComponentNotFound.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComponentNotFound.esm.js","sources":["../../../src/components/ComponentNotFound/ComponentNotFound.tsx"],"sourcesContent":["/*\r\nCopyright 2024 Julio Fernandez\r\n\r\nLicensed under the Apache License, Version 2.0 (the \"License\");\r\nyou may not use this file except in compliance with the License.\r\nYou may obtain a copy of the License at\r\n\r\n http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nUnless required by applicable law or agreed to in writing, software\r\ndistributed under the License is distributed on an \"AS IS\" BASIS,\r\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nSee the License for the specific language governing permissions and\r\nlimitations under the License.\r\n*/\r\nimport React from 'react'\r\nimport { Entity } from '@backstage/catalog-model'\r\nimport { CodeSnippet } from '@backstage/core-components'\r\nimport { Button, Grid, Typography } from '@material-ui/core'\r\nimport KwirthComponentNotFound from '../../assets/kwirthmetrics-component-not-found.svg'\r\nimport { ANNOTATION_KWIRTH_LOCATION } from '@jfvilas/plugin-kwirth-common'\r\n\r\nenum ErrorType {\r\n NO_PODS,\r\n NO_CLUSTERS\r\n}\r\n\r\nconst KUBERNETES_YAML = `apiVersion: apps/v1\r\nkind: Deployment\r\nmetadata:\r\n name: '$entityName'\r\n description: '$entityDescription'\r\n labels:\r\n ${ANNOTATION_KWIRTH_LOCATION} : '$entityName'\r\nspec:\r\n selector:\r\n matchLabels:\r\n app: '$entityName'\r\n template:\r\n metadata:\r\n name: '$entityName'-pod\r\n labels:\r\n app: '$entityName'\r\n ${ANNOTATION_KWIRTH_LOCATION} : '$entityName'\r\n spec:\r\n containers:\r\n - name: '$entityName'\r\n image: your-OCI-image\r\n ...`;\r\n\r\nconst ComponentNotFound = (props: {error: ErrorType, entity:Entity}) => {\r\n var text:string='';\r\n var content:JSX.Element=<CodeSnippet\r\n text={KUBERNETES_YAML.replaceAll('$entityName', props.entity.metadata.name).replaceAll('$entityDescription',props.entity.metadata.description!)}\r\n language=\"yaml\"\r\n showLineNumbers\r\n highlightedNumbers={[7, 17]}\r\n customStyle={{ background: 'inherit' }}\r\n />;\r\n\r\n var nopodsMsg=`Although this component is well tagged, and we have found some clusters configured in Backstage, we were unable to find \"${props.entity.metadata.name}\" running on any pod. Maybe you need to tag Kubernetes objects (deployment and pod templates).`;\r\n var noclustersMsg=`Although this component has a correct 'kubernetes-id' in the ${props.entity.metadata.name} Component YAML, we couldn't find any cluster. Maybe you need to tag Kubernetes objects (deployments and pod templates).`;\r\n \r\n switch(props.error) {\r\n case ErrorType.NO_PODS:\r\n text=nopodsMsg;\r\n break;\r\n case ErrorType.NO_CLUSTERS:\r\n text=noclustersMsg;\r\n break;\r\n }\r\n\r\n return (<>\r\n <Grid container direction=\"row\" justifyContent=\"flex-start\" alignItems=\"flex-start\" spacing={2} >\r\n <Grid item xs={6} md={6}>\r\n <Grid container direction=\"column\">\r\n <Grid item xs>\r\n <Typography variant=\"h5\">{'Component not found'}</Typography>\r\n </Grid>\r\n <Grid item xs>\r\n <Typography variant=\"body1\">{text}</Typography>\r\n </Grid>\r\n <Grid item xs>\r\n {content}\r\n </Grid>\r\n </Grid>\r\n </Grid>\r\n {\r\n <img src={KwirthComponentNotFound} style={{ left:'10%', marginTop:'10%', width:'30%', position:'relative' }} />\r\n }\r\n </Grid>\r\n <Button variant=\"contained\" color=\"primary\" target=\"_blank\" href=\"https://backstage.io/docs/features/kubernetes/configuration#surfacing-your-kubernetes-components-as-part-of-an-entity\">\r\n READ MORE\r\n </Button>\r\n </>);\r\n}\r\n\r\nexport { ComponentNotFound, ErrorType }"],"names":["ErrorType"],"mappings":";;;;;;AAsBK,IAAA,SAAA,qBAAAA,UAAL,KAAA;AACE,EAAAA,UAAA,CAAA,UAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAA;AACA,EAAAA,UAAA,CAAA,UAAA,CAAA,aAAA,CAAA,GAAA,CAAA,CAAA,GAAA,aAAA;AAFG,EAAAA,OAAAA,UAAAA;AAAA,CAAA,EAAA,SAAA,IAAA,EAAA;AAKL,MAAM,eAAkB,GAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,EAMlB,0BAA0B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAAA,EAUtB,0BAA0B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAAA,CAAA;AAO9B,MAAA,iBAAA,GAAoB,CAAC,KAA6C,KAAA;AACpE,EAAA,IAAI,IAAY,GAAA,EAAA;AAChB,EAAA,IAAI,OAAoB,mBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACvB,IAAM,EAAA,eAAA,CAAgB,UAAW,CAAA,aAAA,EAAe,MAAM,MAAO,CAAA,QAAA,CAAS,IAAI,CAAA,CAAE,UAAW,CAAA,oBAAA,EAAqB,KAAM,CAAA,MAAA,CAAO,SAAS,WAAY,CAAA;AAAA,MAC9I,QAAS,EAAA,MAAA;AAAA,MACT,eAAe,EAAA,IAAA;AAAA,MACf,kBAAA,EAAoB,CAAC,CAAA,EAAG,EAAE,CAAA;AAAA,MAC1B,WAAA,EAAa,EAAE,UAAA,EAAY,SAAU;AAAA;AAAA,GACvC;AAEA,EAAA,IAAI,SAAU,GAAA,CAAA,yHAAA,EAA4H,KAAM,CAAA,MAAA,CAAO,SAAS,IAAI,CAAA,8FAAA,CAAA;AACpK,EAAA,IAAI,aAAc,GAAA,CAAA,6DAAA,EAAgE,KAAM,CAAA,MAAA,CAAO,SAAS,IAAI,CAAA,wHAAA,CAAA;AAE5G,EAAA,QAAO,MAAM,KAAO;AAAA,IAClB,KAAK,CAAA;AACH,MAAK,IAAA,GAAA,SAAA;AACL,MAAA;AAAA,IACF,KAAK,CAAA;AACH,MAAK,IAAA,GAAA,aAAA;AACL,MAAA;AAAA;AAGJ,EAAA,iFACK,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,WAAS,IAAC,EAAA,SAAA,EAAU,OAAM,cAAe,EAAA,YAAA,EAAa,YAAW,YAAa,EAAA,OAAA,EAAS,qBACxF,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,MAAI,IAAC,EAAA,EAAA,EAAI,GAAG,EAAI,EAAA,CAAA,EAAA,sCACjB,IAAK,EAAA,EAAA,SAAA,EAAS,MAAC,SAAU,EAAA,QAAA,EAAA,sCACrB,IAAK,EAAA,EAAA,IAAA,EAAI,MAAC,EAAE,EAAA,IAAA,EAAA,sCACZ,UAAW,EAAA,EAAA,OAAA,EAAQ,QAAM,qBAAsB,CAChD,mBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,MAAI,IAAC,EAAA,EAAA,EAAE,wBACZ,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,SAAQ,OAAS,EAAA,EAAA,IAAK,CAClC,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,IAAI,EAAA,IAAA,EAAC,IAAE,IACZ,EAAA,EAAA,OACD,CACJ,CACJ,CAAA,sCAEG,KAAI,EAAA,EAAA,GAAA,EAAK,yBAAyB,KAAO,EAAA,EAAE,MAAK,KAAO,EAAA,SAAA,EAAU,OAAO,KAAM,EAAA,KAAA,EAAO,UAAS,UAAW,EAAA,EAAG,CAEnH,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAO,OAAQ,EAAA,WAAA,EAAY,OAAM,SAAU,EAAA,MAAA,EAAO,UAAS,IAAK,EAAA,uHAAA,EAAA,EAAwH,WAEzL,CACJ,CAAA;AACJ;;;;"}
|