{
+
+ render() {
+ const { object: k8c } = this.props;
+ if (!k8c) return null;
+
+ var datacentersStatus = Object.keys(k8c.status.datacenters).map(dc => {
+ if (k8c.status.datacenters[dc].cassandra.conditions) {
+ return
+ {k8c.status.datacenters[dc].cassandra.conditions.map((condition, index) => {
+ const { type, reason, message, status } = condition;
+ const kind = type || reason;
+ if (!kind) return null;
+ if (status === "False") return null;
+ return (
+
+ );
+ })}
+
+ } else {
+ return null;
+ }
+ }
+ );
+
+ const cassandraYamlHeader = ;
+ const jvmOptionsHeader = ;
+
+ var clusterCassandraYaml = ;
+ var clusterJvmOptions = ;
+
+ if (k8c.spec.cassandra.config) {
+ if (k8c.spec.cassandra.config.cassandraYaml) {
+ clusterCassandraYaml =
+
+ {cassandraYamlHeader}
+ {displayCassandraYaml(k8c.spec.cassandra.config.cassandraYaml)}
+
;
+ }
+ if (k8c.spec.cassandra.config.jvmOptions) {
+ clusterJvmOptions =
+
+ {jvmOptionsHeader}
+ {displayJvmOptions(k8c.spec.cassandra.config.jvmOptions)}
+
;
+ }
+ }
+
+ var storageConfig = ;
+ if (k8c.spec.cassandra.storageConfig) {
+ storageConfig = displayStorageConfig(k8c.spec.cassandra.storageConfig);
+ }
+
+ var datacentersDetails = k8c.spec.cassandra.datacenters.map(dc => {
+ const dcHeader = {dc.metadata.name}
;
+ if (dc.config) {
+
+ var cassandraYaml = ;
+ if (dc.config.cassandraYaml) {
+ cassandraYaml =
+ {cassandraYamlHeader}
+ {displayCassandraYaml(k8c.spec.cassandra.config.cassandraYaml)}
+
;
+ }
+
+ var jvmOptions = ;
+ if (dc.config.jvmOptions) {
+ jvmOptions =
+ {jvmOptionsHeader}
+ {displayJvmOptions(dc.config.jvmOptions)}
+
;
+ }
+ }
+
+ var dcStorageConfig = ;
+ if (dc.storageConfig) {
+ dcStorageConfig = displayStorageConfig(dc.storageConfig);
+ }
+
+ return
+ {dcHeader}
+ {dc.size}
+ {dc.stopped}
+ {dcStorageConfig}
+ {cassandraYaml}
+ {jvmOptions}
});
+
+
+ return (
+
+
+ {k8c.getAge(true, false)} ago ({k8c.metadata.creationTimestamp })
+
+
+ {k8c.spec.cassandra.datacenters.length}
+
+
+ {k8c.spec.cassandra.serverVersion}
+
+ {storageConfig}
+
{datacentersStatus}
+
{clusterCassandraYaml}
+
{clusterJvmOptions}
+
{datacentersDetails}
+
+ )
+ }
+}
+
+function displayCassandraYaml(cassandraYaml: K8ssandraCluster["spec"]["cassandra"]["config"]["cassandraYaml"]) {
+ return
+
+
+ Setting
+ Value
+
+ {Object.keys(cassandraYaml).map((key, index) => {
+ return (
+ {key}
+ {JSON.stringify(cassandraYaml[key])}
+ );
+ })}
+
+
;
+}
+
+function displayJvmOptions(jvmOptions: K8ssandraCluster["spec"]["cassandra"]["config"]["jvmOptions"]) {
+ return
+
+
+ Setting
+ Value
+
+ {Object.keys(jvmOptions).map((key, index) => {
+ return (
+ {key}
+ {jvmOptions[key]}
+ );
+ })}
+
+
;
+}
+
+function displayStorageConfig(storageConfig: K8ssandraCluster["spec"]["cassandra"]["storageConfig"]) {
+ return
+ {storageConfig.cassandraDataVolumeClaimSpec.storageClassName}
+ {storageConfig.cassandraDataVolumeClaimSpec.resources.requests.storage}
+ {storageConfig.cassandraDataVolumeClaimSpec.accessModes.join(" - ")}
+
;
+}
\ No newline at end of file
diff --git a/k8ssandra/src/components/k8c-page.tsx b/k8ssandra/src/components/k8c-page.tsx
new file mode 100644
index 0000000..853911f
--- /dev/null
+++ b/k8ssandra/src/components/k8c-page.tsx
@@ -0,0 +1,157 @@
+import { Renderer } from "@k8slens/extensions";
+import React from "react";
+import { k8ssandraClusterStore } from "../k8c-store";
+import { K8ssandraCluster } from "../k8c"
+
+const {
+ Component: {
+ KubeObjectListLayout,
+ Badge
+ }
+} = Renderer;
+
+enum sortBy {
+ name = "name",
+ namespace = "namespace"
+}
+
+export class K8ssandraClusterPage extends React.Component<{ extension: Renderer.LensExtension }> {
+
+ render() {
+ return (
+ k8c.getName(),
+ [sortBy.namespace]: (k8c: K8ssandraCluster) => k8c.metadata.namespace,
+ }}
+ searchFilters={[
+ (k8c: K8ssandraCluster) => k8c.getSearchFields()
+ ]}
+ renderHeaderTitle="Cassandra Datacenters"
+ renderTableHeader={[
+ {title: "Name", className: "name", sortBy: sortBy.name},
+ {title: "Namespace", className: "namespace", sortBy: sortBy.namespace},
+ {title: "Version", className: "Version"},
+ {title: "Datacenters", className: "Size"},
+ {title: "Progress", className: "progress"},
+ {title: "Reaper", className: "progress"},
+ {title: "Stargate", className: "progress"},
+ ]}
+ renderTableContents={(k8c: K8ssandraCluster) => [
+ k8c.getName(),
+ k8c.metadata.namespace,
+ k8c.spec.cassandra.serverVersion,
+ k8c.spec.cassandra.datacenters.length,
+ renderProgress(k8c.status),
+ renderReaperProgress(k8c.status),
+ renderStargateProgress(k8c.status),
+ ]}
+ />
+ )
+ }
+}
+
+function renderProgress(k8cStatus: K8ssandraCluster["status"]) {
+ var dcStatuses = new Map>();
+ if (k8cStatus.datacenters) {
+ Object.entries(k8cStatus.datacenters).forEach((dcStatus, _) => {
+ console.log("Reading dcStatus for " + dcStatus[0]);
+ const progress = dcStatus[1].cassandra.cassandraOperatorProgress;
+ var className = "info";
+ switch (progress) {
+ case "Ready":
+ className = "success";
+ break;
+ case "Updating":
+ className = "warning";
+ break;
+ }
+ let dcState = new Map([
+ ["className", className],
+ ["progress", progress]
+ ]);
+ dcStatuses.set(dcStatus[0], dcState);
+ });
+ };
+
+ var badges = Array.from(dcStatuses.keys()).map(dc => {
+ console.log("dcStatus for " + dc + " : " + dcStatuses.get(dc).get("progress") + "/" + dcStatuses.get(dc).get("className"));
+ return (
+
+ );
+ })
+
+ return {badges}
;
+}
+
+function renderReaperProgress(k8cStatus: K8ssandraCluster["status"]) {
+ var reaperStatuses = new Map>();
+ if (k8cStatus.datacenters) {
+ Object.entries(k8cStatus.datacenters).forEach((dcStatus, _) => {
+ if (dcStatus[1].reaper) {
+ const progress = dcStatus[1].reaper.progress;
+ var className = "info";
+ switch (progress) {
+ case "Running":
+ className = "success";
+ break;
+ }
+ let reaperState = new Map([
+ ["className", className],
+ ["progress", progress]
+ ]);
+ reaperStatuses.set(dcStatus[0], reaperState);
+ }
+ });
+ };
+
+ var badges = Array.from(reaperStatuses.keys()).map(dc => {
+ return (
+
+ );
+ })
+
+ return {badges}
;
+}
+
+function renderStargateProgress(k8cStatus: K8ssandraCluster["status"]) {
+ var stargateStatuses = new Map>();
+ if (k8cStatus.datacenters) {
+ Object.entries(k8cStatus.datacenters).forEach((dcStatus, _) => {
+ if (dcStatus[1].stargate) {
+ const progress = dcStatus[1].stargate.progress;
+ var className = "info";
+ switch (progress) {
+ case "Running":
+ className = "success";
+ break;
+ }
+ let stargateState = new Map([
+ ["className", className],
+ ["progress", progress],
+ ["readyReplicasRatio", dcStatus[1].stargate.readyReplicasRatio]
+ ]);
+ stargateStatuses.set(dcStatus[0], stargateState);
+ }
+ });
+ };
+
+ var badges = Array.from(stargateStatuses.keys()).map(dc => {
+ return (
+
+ );
+ })
+
+ return {badges}
;
+}
\ No newline at end of file
diff --git a/k8ssandra/src/k8c-store.ts b/k8ssandra/src/k8c-store.ts
new file mode 100644
index 0000000..c6a86a6
--- /dev/null
+++ b/k8ssandra/src/k8c-store.ts
@@ -0,0 +1,14 @@
+import { Renderer} from "@k8slens/extensions";
+import { K8ssandraCluster } from "./k8c";
+
+export class K8ssandraClusterApi extends Renderer.K8sApi.KubeApi {
+}
+
+export class K8ssandraClusterStore extends Renderer.K8sApi.KubeObjectStore {
+ api = new K8ssandraClusterApi({
+ objectConstructor: K8ssandraCluster
+ })
+}
+
+export const k8ssandraClusterStore = new K8ssandraClusterStore();
+Renderer.K8sApi.apiManager.registerStore(k8ssandraClusterStore);
diff --git a/k8ssandra/src/k8c.ts b/k8ssandra/src/k8c.ts
new file mode 100644
index 0000000..8574a8b
--- /dev/null
+++ b/k8ssandra/src/k8c.ts
@@ -0,0 +1,80 @@
+import { Renderer} from "@k8slens/extensions";
+
+export class K8ssandraCluster extends Renderer.K8sApi.KubeObject {
+ static kind = "K8ssandraCluster"
+ static namespaced = true
+ static apiBase = "/apis/k8ssandra.io/v1alpha1/k8ssandraclusters"
+
+ kind: string
+ apiVersion: string
+ metadata: {
+ name: string;
+ namespace: string;
+ selfLink: string;
+ uid: string;
+ resourceVersion: string;
+ creationTimestamp: string;
+ labels: {
+ [key: string]: string;
+ };
+ annotations: {
+ [key: string]: string;
+ };
+ }
+ spec: {
+ cassandra: {
+ config: {
+ cassandraYaml: {
+ [key: string]: any;
+ },
+ jvmOptions: {
+ [key: string]: string;
+ },
+ },
+ datacenters: {
+ config: K8ssandraCluster["spec"]["cassandra"]["config"];
+ size: number;
+ metadata: {
+ name: string;
+ },
+ stopped: boolean;
+ storageConfig: K8ssandraCluster["spec"]["cassandra"]["storageConfig"];
+ }[];
+ serverVersion: string;
+ storageConfig: {
+ cassandraDataVolumeClaimSpec: {
+ accessModes: string[];
+ resources: {
+ requests: {
+ storage: string;
+ };
+ };
+ storageClassName: string;
+ };
+ };
+ }
+ }
+ status: {
+ datacenters: {
+ [key: string]: {
+ cassandra: {
+ conditions: {
+ lastTransitionTime: string;
+ message: string;
+ reason: string;
+ status: string;
+ type?: string;
+ }[];
+ cassandraOperatorProgress: string;
+ },
+ reaper: {
+ progress: string;
+ }
+ stargate: {
+ progress: string;
+ readyReplicasRatio: string;
+ }
+ }
+ }
+ }
+}