package render import ( "context" "strings" "github.com/weaveworks/scope/report" ) // KubernetesVolumesRenderer is a Renderer which combines all Kubernetes // volumes components such as stateful Pods, Persistent Volume, Persistent Volume Claim, Storage Class. var KubernetesVolumesRenderer = MakeReduce( VolumesRenderer, PodToVolumeRenderer, PVCToStorageClassRenderer, PVToSnapshotRenderer, VolumeSnapshotRenderer, ) // VolumesRenderer is a Renderer which produces a renderable kubernetes PV & PVC // graph by merging the pods graph and the Persistent Volume topology. var VolumesRenderer = volumesRenderer{} // volumesRenderer is a Renderer to render PV & PVC nodes. type volumesRenderer struct{} // Render renders PV & PVC nodes along with adjacency func (v volumesRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for id, n := range rpt.PersistentVolumeClaim.Nodes { volume, _ := n.Latest.Lookup(report.KubernetesVolumeName) for _, p := range rpt.PersistentVolume.Nodes { volumeName, _ := p.Latest.Lookup(report.KubernetesName) if volume == volumeName { n.Adjacency = n.Adjacency.Add(p.ID) n.Children = n.Children.Add(p) } } nodes[id] = n } return Nodes{Nodes: nodes} } // PodToVolumeRenderer is a Renderer which produces a renderable kubernetes Pod // graph by merging the pods graph and the Persistent Volume Claim topology. // Pods having persistent volumes are rendered. var PodToVolumeRenderer = podToVolumesRenderer{} // VolumesRenderer is a Renderer to render Pods & PVCs. type podToVolumesRenderer struct{} // Render renders the Pod nodes having volumes adjacency. func (v podToVolumesRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for podID, podNode := range rpt.Pod.Nodes { claimNames, found := podNode.Latest.Lookup(report.KubernetesVolumeClaim) if !found { continue } podNamespace, _ := podNode.Latest.Lookup(report.KubernetesNamespace) claimNameList := strings.Split(claimNames, report.ScopeDelim) for _, ClaimName := range claimNameList { for _, pvcNode := range rpt.PersistentVolumeClaim.Nodes { pvcName, _ := pvcNode.Latest.Lookup(report.KubernetesName) pvcNamespace, _ := pvcNode.Latest.Lookup(report.KubernetesNamespace) if (pvcName == ClaimName) && (podNamespace == pvcNamespace) { podNode.Adjacency = podNode.Adjacency.Add(pvcNode.ID) podNode.Children = podNode.Children.Add(pvcNode) break } } } nodes[podID] = podNode } return Nodes{Nodes: nodes} } // PVCToStorageClassRenderer is a Renderer which produces a renderable kubernetes PVC // & Storage class graph. var PVCToStorageClassRenderer = pvcToStorageClassRenderer{} // pvcToStorageClassRenderer is a Renderer to render PVC & StorageClass. type pvcToStorageClassRenderer struct{} // Render renders the PVC & Storage Class nodes with adjacency. func (v pvcToStorageClassRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for scID, scNode := range rpt.StorageClass.Nodes { storageClass, _ := scNode.Latest.Lookup(report.KubernetesName) for _, pvcNode := range rpt.PersistentVolumeClaim.Nodes { storageClassName, _ := pvcNode.Latest.Lookup(report.KubernetesStorageClassName) if storageClassName == storageClass { scNode.Adjacency = scNode.Adjacency.Add(pvcNode.ID) scNode.Children = scNode.Children.Add(pvcNode) } } nodes[scID] = scNode } return Nodes{Nodes: nodes} } //PVToSnapshotRenderer is a Renderer which produces a renderable kubernetes PV var PVToSnapshotRenderer = pvToSnapshotRenderer{} //pvToSnapshotRenderer is a Renderer to render PV & Snapshot. type pvToSnapshotRenderer struct{} //Render renders the PV & Snapshot nodes with adjacency. func (v pvToSnapshotRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for pvNodeID, p := range rpt.PersistentVolume.Nodes { volumeName, _ := p.Latest.Lookup(report.KubernetesName) for _, volumeSnapshotNode := range rpt.VolumeSnapshot.Nodes { snapshotPVName, _ := volumeSnapshotNode.Latest.Lookup(report.KubernetesVolumeName) if volumeName == snapshotPVName { p.Adjacency = p.Adjacency.Add(volumeSnapshotNode.ID) p.Children = p.Children.Add(volumeSnapshotNode) } } nodes[pvNodeID] = p } return Nodes{Nodes: nodes} } // VolumeSnapshotRenderer is a renderer which produces a renderable Kubernetes Volume Snapshot and Volume Snapshot Data var VolumeSnapshotRenderer = volumeSnapshotRenderer{} // volumeSnapshotRenderer is a render to volume snapshot & volume snapshot data type volumeSnapshotRenderer struct{} // Render renders the volumeSnapshots & volumeSnapshotData with adjacency // It checks for the volumeSnapshotData name in volumeSnapshot, adjacency is created by matching the volumeSnapshotData name. func (v volumeSnapshotRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for volumeSnapshotID, volumeSnapshotNode := range rpt.VolumeSnapshot.Nodes { snapshotData, _ := volumeSnapshotNode.Latest.Lookup(report.KubernetesSnapshotData) for volumeSnapshotDataID, volumeSnapshotDataNode := range rpt.VolumeSnapshotData.Nodes { snapshotDataName, _ := volumeSnapshotDataNode.Latest.Lookup(report.KubernetesName) if snapshotDataName == snapshotData { volumeSnapshotNode.Adjacency = volumeSnapshotNode.Adjacency.Add(volumeSnapshotDataNode.ID) volumeSnapshotNode.Children = volumeSnapshotNode.Children.Add(volumeSnapshotDataNode) } nodes[volumeSnapshotDataID] = volumeSnapshotDataNode } nodes[volumeSnapshotID] = volumeSnapshotNode } return Nodes{Nodes: nodes} }