diff --git a/docs/extensions/guides/README.md b/docs/extensions/guides/README.md index 2f04edfea1..0e15268611 100644 --- a/docs/extensions/guides/README.md +++ b/docs/extensions/guides/README.md @@ -14,6 +14,7 @@ Each guide or sample will include: | Guide | APIs | | ----- | ----- | +| [Generate new extension project](generator.md) || | [Main process extension](main-extension.md) | LensMainExtension | | [Renderer process extension](renderer-extension.md) | LensRendererExtension | | [Stores](stores.md) | | @@ -27,3 +28,7 @@ Each guide or sample will include: | ----- | ----- | [helloworld](https://github.com/lensapp/lens-extension-samples/tree/master/helloworld-sample) | LensMainExtension
LensRendererExtension
Component.Icon
Component.IconProps | [minikube](https://github.com/lensapp/lens-extension-samples/tree/master/minikube-sample) | LensMainExtension
Store.clusterStore
Store.workspaceStore | +[styling-css-modules-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-css-modules-sample) | LensMainExtension
LensRendererExtension
Component.Icon
Component.IconProps | +[styling-emotion-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-emotion-sample) | LensMainExtension
LensRendererExtension
Component.Icon
Component.IconProps | +[styling-sass-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-sass-sample) | LensMainExtension
LensRendererExtension
Component.Icon
Component.IconProps | +[custom-resource-page](https://github.com/lensapp/lens-extension-samples/tree/master/custom-resource-page) | LensRendererExtension
K8sApi.KubeApi
K8sApi.KubeObjectStore
Component.KubeObjectListLayout
Component.KubeObjectDetailsProps
Component.IconProps | diff --git a/docs/extensions/guides/renderer-extension.md b/docs/extensions/guides/renderer-extension.md index 8d02fb9cef..1e595d004f 100644 --- a/docs/extensions/guides/renderer-extension.md +++ b/docs/extensions/guides/renderer-extension.md @@ -269,7 +269,115 @@ export class HelpPage extends React.Component<{ extension: LensRendererExtension `HelpIcon` introduces one of Lens' built-in components available to extension developers, the `Component.Icon`. Built in are the [Material Design](https://material.io) [icons](https://material.io/resources/icons/). One can be selected by name via the `material` field. +### `clusterFeatures` +Cluster features are Kubernetes resources that can be applied to and managed within the active cluster. They can be installed/uninstalled by the Lens user from the [cluster settings page](). +The following example shows how to add a cluster feature as part of a `LensRendererExtension`: + +``` typescript +import { LensRendererExtension } from "@k8slens/extensions" +import { ExampleFeature } from "./src/example-feature" +import React from "react" + +export default class ExampleFeatureExtension extends LensRendererExtension { + clusterFeatures = [ + { + title: "Example Feature", + components: { + Description: () => { + return ( + + Enable an example feature. + + ) + } + }, + feature: new ExampleFeature() + } + ]; +} +``` +The `title` and `components.Description` fields provide content that appears on the cluster settings page, in the **Features** section. The `feature` field must specify an instance which extends the abstract class `ClusterFeature.Feature`, and specifically implement the following methods: + +``` typescript + abstract install(cluster: Cluster): Promise; + abstract upgrade(cluster: Cluster): Promise; + abstract uninstall(cluster: Cluster): Promise; + abstract updateStatus(cluster: Cluster): Promise; +``` + +The `install()` method is typically called by Lens when a user has indicated that this feature is to be installed (i.e. clicked **Install** for the feature on the cluster settings page). The implementation of this method should install kubernetes resources using the `applyResources()` method, or by directly accessing the kubernetes api ([`K8sApi`](tbd)). + +The `upgrade()` method is typically called by Lens when a user has indicated that this feature is to be upgraded (i.e. clicked **Upgrade** for the feature on the cluster settings page). The implementation of this method should upgrade the kubernetes resources already installed, if relevant to the feature. + +The `uninstall()` method is typically called by Lens when a user has indicated that this feature is to be uninstalled (i.e. clicked **Uninstall** for the feature on the cluster settings page). The implementation of this method should uninstall kubernetes resources using the kubernetes api (`K8sApi`) + +The `updateStatus()` method is called periodically by Lens to determine details about the feature's current status. The implementation of this method should provide the current status information in the `status` field of the `ClusterFeature.Feature` parent class. The `status.currentVersion` and `status.latestVersion` fields may be displayed by Lens in describing the feature. The `status.installed` field should be set to true if the feature is currently installed, otherwise false. Also, Lens relies on the `status.canUpgrade` field to determine if the feature can be upgraded (i.e a new version could be available) so the implementation should set the `status.canUpgrade` field according to specific rules for the feature, if relevant. + +The following shows a very simple implementation of a `ClusterFeature`: + +``` typescript +import { ClusterFeature, Store, K8sApi } from "@k8slens/extensions"; +import * as path from "path"; + +export class ExampleFeature extends ClusterFeature.Feature { + + async install(cluster: Store.Cluster): Promise { + + super.applyResources(cluster, path.join(__dirname, "../resources/")); + } + + async upgrade(cluster: Store.Cluster): Promise { + return this.install(cluster); + } + + async updateStatus(cluster: Store.Cluster): Promise { + try { + const pod = K8sApi.forCluster(cluster, K8sApi.Pod); + const examplePod = await pod.get({name: "example-pod", namespace: "default"}); + if (examplePod?.kind) { + this.status.installed = true; + this.status.currentVersion = examplePod.spec.containers[0].image.split(":")[1]; + this.status.canUpgrade = true; // a real implementation would perform a check here that is relevant to the specific feature + } else { + this.status.installed = false; + this.status.canUpgrade = false; + } + } catch(e) { + if (e?.error?.code === 404) { + this.status.installed = false; + this.status.canUpgrade = false; + } + } + + return this.status; + } + + async uninstall(cluster: Store.Cluster): Promise { + const podApi = K8sApi.forCluster(cluster, K8sApi.Pod); + await podApi.delete({name: "example-pod", namespace: "default"}); + } +} +``` + +This example implements the `install()` method by simply invoking the helper `applyResources()` method. `applyResources()` tries to apply all resources read from all files found in the folder path provided. In this case this folder path is the `../resources` subfolder relative to current source code's folder. The file `../resources/example-pod.yml` could contain: + +``` yaml +apiVersion: v1 +kind: Pod +metadata: + name: example-pod +spec: + containers: + - name: example-pod + image: nginx +``` + +The `upgrade()` method in the example above is implemented by simply invoking the `install()` method. Depending on the feature to be supported by an extension, upgrading may require additional and/or different steps. + +The `uninstall()` method is implemented in the example above by utilizing the [`K8sApi`](tbd) provided by Lens to simply delete the `example-pod` pod applied by the `install()` method. + +The `updateStatus()` method is implemented above by using the [`K8sApi`](tbd) as well, this time to get information from the `example-pod` pod, in particular to determine if it is installed, what version is associated with it, and if it can be upgraded. How the status is updated for a specific cluster feature is up to the implementation. ********************************************************************* @@ -278,44 +386,6 @@ WIP below! -### `clusterFeatures` - -Cluster features are Kubernetes resources that can applied and managed to the active cluster. They can be installed/uninstalled from the [cluster settings page](). -The following example shows how to add a cluster feature: - -``` typescript -import { LensRendererExtension } from "@k8slens/extensions" -import { MetricsFeature } from "./src/metrics-feature" -import React from "react" - -export default class ClusterMetricsFeatureExtension extends LensRendererExtension { - clusterFeatures = [ - { - title: "Metrics Stack", - components: { - Description: () => { - return ( - - Enable timeseries data visualization (Prometheus stack) for your cluster. - Install this only if you don't have existing Prometheus stack installed. - You can see preview of manifests here. - - ) - } - }, - feature: new MetricsFeature() - } - ]; -} -``` -The `title` and `components.Description` fields appear on the cluster settings page. The cluster feature must extend the abstract class `ClusterFeature.Feature`, and specifically implement the following methods: - -``` typescript - abstract install(cluster: Cluster): Promise; - abstract upgrade(cluster: Cluster): Promise; - abstract uninstall(cluster: Cluster): Promise; - abstract updateStatus(cluster: Cluster): Promise; -``` ### `appPreferences` diff --git a/src/extensions/cluster-feature.ts b/src/extensions/cluster-feature.ts index 4cb2c9bf5a..3ee671e6c5 100644 --- a/src/extensions/cluster-feature.ts +++ b/src/extensions/cluster-feature.ts @@ -47,7 +47,7 @@ export abstract class ClusterFeature { abstract async install(cluster: Cluster): Promise; /** - * to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be ugraded. The implementation + * to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be upgraded. The implementation * of this method should upgrade the kubernetes resources already installed, if relevant to the feature * * @param cluster the cluster that the feature is to be upgraded on @@ -56,7 +56,7 @@ export abstract class ClusterFeature { /** * to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be uninstalled. The implementation - * of this method should install kubernetes resources using the kubernetes api (K8sApi) + * of this method should uninstall kubernetes resources using the kubernetes api (K8sApi) * * @param cluster the cluster that the feature is to be uninstalled from */