/** * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ import jsyaml from "js-yaml"; import { observer } from "mobx-react"; import React from "react"; import { Link } from "react-router-dom"; import type { RequireAllOrNone } from "type-fest"; import { configMapApi, Pod, PodVolume, PodVolumeKind, PodVolumeVariants, pvcApi, SecretReference, secretsApi } from "../../../common/k8s-api/endpoints"; import type { KubeApi } from "../../../common/k8s-api/kube-api"; import type { KubeObject, LocalObjectReference } from "../../../common/k8s-api/kube-object"; import { entries } from "../../utils"; import { DrawerItem, DrawerItemLabels, DrawerTitle } from "../drawer"; import { Icon } from "../icon"; import { getDetailsUrl } from "../kube-detail-params"; /** * Additional parameters for each volume variant */ export interface VariantOptions { pod: Pod; volumeName: string; } function renderLocalRef(pod: Pod, title: string, ref: LocalObjectReference | SecretReference, typeApi: KubeApi) { return ( {ref.name} ); } /** * */ type PodVolumeVariantRenderers = { [Key in keyof PodVolumeVariants]: (variant: PodVolumeVariants[Key], opts: VariantOptions) => React.ReactChild; }; const volumeRenderers: PodVolumeVariantRenderers = { awsElasticBlockStore: ({ volumeID, fsType = "ext4" }) => ( <> {volumeID} {fsType} ), azureDisk: ({ diskName, diskURI, kind = "Shared", cachingMode = "None", fsType = "ext4", readonly = false }) => ( <> {diskName} {diskURI} {kind} {cachingMode} {fsType} {readonly.toString()} ), azureFile: ({ readOnly = false, secretName, shareName, secretNamespace = "default" }) => ( <> {secretName} {shareName} {secretNamespace} {readOnly.toString()} ), ephemeral: ({ volumeClaimTemplate: { metadata, spec }}, { pod, volumeName }) => ( <> {pod.getName()}-{volumeName} {jsyaml.dump(spec)} ), emptyDir: ({ medium, sizeLimit }) => ( <> ), cephfs: ({ monitors, path = "/", user = "admin", secretFile = "/etc/ceph/user.secret", secretRef, readOnly }, { pod }) => ( <>
    {monitors.map(monitor =>
  • {monitor}
  • )}
{path} {user} { secretRef ? renderLocalRef(pod, "Secret", secretRef, secretsApi) : ( {secretFile} ) } {readOnly.toString()} ), cinder: ({ volumeID, fsType = "ext4" }) => ( <> {volumeID} {fsType} ), configMap: ({ name }, { pod }) => renderLocalRef(pod, "Name", { name }, configMapApi), downwardAPI: ({ items }) => ( <>
    {items.map(item =>
  • {item.path}
  • )}
), fc: ({ targetWWNs, lun, fsType = "ext4", readOnly = false }) => ( <>
    {targetWWNs.map(targetWWN =>
  • {targetWWN}
  • )}
{lun.toString()} {fsType} {readOnly.toString()} ), flexVolume: ({ driver, fsType, secretRef, readOnly = false, options }, { pod }) => ( <> {driver} {fsType || "-- system default --"} {secretRef && renderLocalRef(pod, "Secret", secretRef, secretsApi)} {readOnly.toString()} { ...Object.entries(options) .map(([key, value]) => ( {value} )) } ), flocker: ({ datasetName }) => ( <> {datasetName} ), gcePersistentDisk: ({ pdName, fsType = "ext4" }) => ( <> {pdName} {fsType} ), gitRepo: ({ repository, revision }) => ( <> {repository} {revision} ), glusterfs: ({ endpoints, path, readOnly = false }) => ( <> {endpoints} {path} {readOnly.toString()} ), hostPath: ({ path, type }) => ( <> {path} {type || "-- none --"} ), iscsi: ({ targetPortal, iqn, lun, fsType = "ext4", readOnly = false, chapAuthDiscovery, chapAuthSession, secretRef }) => ( <> {targetPortal} {iqn} {lun.toString()} {fsType} {readOnly.toString()} {chapAuthDiscovery && ( {chapAuthDiscovery.toString()} )} {chapAuthSession && ( {chapAuthSession.toString()} )} { secretRef && ( {secretRef.name} )} ), local: ({ path }) => ( <> {path} ), nfs: ({ server, path, readOnly = false }) => ( <> {server} {path} {readOnly.toString()} ), persistentVolumeClaim: ({ claimName }, { pod }) => renderLocalRef(pod, "Name", { name: claimName }, pvcApi), photonPersistentDisk: ({ pdID, fsType = "ext4" }) => ( <> {pdID} {fsType} ), portworxVolume: ({ volumeID, fsType = "ext4", readOnly = false }) => ( <> {volumeID} {fsType} {readOnly.toString()} ), projected: ({ sources, defaultMode }) => ( <> 0o{defaultMode.toString(8)} { sources.map(({ secret, downwardAPI, configMap, serviceAccountToken }, index) => ( {secret && ( <> Secret {secret.name} {secret.items && (
    {secret.items.map(({ key }) =>
  • {key}
  • )}
)} )} {downwardAPI && ( <> Downward API {downwardAPI.items && (
    {downwardAPI.items.map(({ path }) =>
  • {path}
  • )}
)} )} {configMap && ( <> Config Map {configMap.name} {configMap.items && (
    {configMap.items.map(({ path }) =>
  • {path}
  • )}
)} )} {serviceAccountToken && ( <> Service Account Token {serviceAccountToken.path} )}
)) }
), quobyte: ({ registry, volume, readOnly = false, user = "serviceaccount", group, tenant }) => ( <> {registry} {volume} {readOnly.toString()} {user} {group ?? "-- no group --"} ), rbd: ({ monitors, image, fsType = "ext4", pool = "rbd", user = "admin", keyring = "/etc/ceph/keyright", secretRef, readOnly = false }, { pod }) => ( <>
    {monitors.map(monitor =>
  • {monitor}
  • )}
{image} {fsType} {pool} {user} { secretRef ? renderLocalRef(pod, "Authentication Secret", secretRef, secretsApi) : ( {keyring} ) } {readOnly.toString()} ), scaleIO: ({ gateway, system, secretRef, sslEnabled = false, protectionDomain, storagePool, storageMode = "ThinProvisioned", volumeName, fsType = "xfs", readOnly = false }, { pod }) => ( <> {gateway} {system} {renderLocalRef(pod, "Name", secretRef, secretsApi)} {sslEnabled.toString()} {sslEnabled.toString()} {volumeName} {fsType} {readOnly.toString()} ), secret: ({ secretName, items = [], defaultMode = 0o644, optional = false }, { pod }) => ( <> {renderLocalRef(pod, "Name", { name: secretName }, secretsApi)} 0o{defaultMode.toString(8)} {optional.toString()} ), storageos: ({ volumeName, volumeNamespace, fsType = "ext4", readOnly = false, secretRef }, { pod }) => ( <> {volumeName} {fsType} {readOnly.toString()} {secretRef && renderLocalRef(pod, "Secret", secretRef, secretsApi)} ), vsphereVolume: ({ volumePath, fsType = "ext4", storagePolicyName, storagePolicyID }) => ( <> {volumePath} {fsType} ), csi: ({ driver, readOnly = false, fsType = "ext4", volumeAttributes = {}, nodePublishSecretRef, controllerPublishSecretRef, nodeStageSecretRef, controllerExpandSecretRef }, { pod }) => ( <> {driver} {readOnly.toString()} {fsType} {controllerPublishSecretRef && renderLocalRef(pod, "Controller Publish Secret", controllerPublishSecretRef, secretsApi)} {controllerExpandSecretRef && renderLocalRef(pod, "Controller Expand Secret", controllerExpandSecretRef, secretsApi)} {nodePublishSecretRef && renderLocalRef(pod, "Node Publish Secret", nodePublishSecretRef, secretsApi)} {nodeStageSecretRef && renderLocalRef(pod, "Node Stage Secret", nodeStageSecretRef, secretsApi)} { ...Object.entries(volumeAttributes) .map(([key, value]) => ( {value} )) } ), }; export interface PodVolumesProps { pod: Pod; } const deprecatedVolumeTypes = new Set([ "flocker", "gitRepo", "quobyte", "storageos", ]); interface VolumeRendererPair { kind: PodVolumeKind; render: () => React.ReactChild; } function getVolumeType(pod: Pod, volume: PodVolume): RequireAllOrNone { for (const [kind, varient] of entries(volume)) { if (kind === "name") { continue; // This key is not a kind field } if (!varient || typeof varient !== "object") { continue; } return { kind, render: () => volumeRenderers[kind](varient as never, { pod, volumeName: volume.name }), }; } return {}; } export const PodVolumes = observer(({ pod }: PodVolumesProps) => { if (!pod) { return null; } const renderVolume = (volume: PodVolume) => { const { kind, render } = getVolumeType(pod, volume); const isDeprecated = deprecatedVolumeTypes.has(kind); console.log(volume, render); return (
{volume.name}
{ kind ? ( <> {kind} {isDeprecated && } {render?.()} ) :

Error! Unknown pod volume kind

}
); }; const volumes = pod.getVolumes(); if (volumes.length === 0) { return null; } return ( <> Volumes {volumes.map(renderVolume)} ); });