mirror of
https://github.com/weaveworks/scope.git
synced 2026-08-18 11:56:39 +00:00
Add kubernetes volume snapshot support
- Add a new client in probe/kubernetes/client.go which will be used to fetch details of Snapshot CRD - Visualize VolumeSnapshot and VolumeSnapshotData - Add adjacency between PV and VolumeSnapshot - Add adjacency between VolumeSnapshot and VolumeSnapshotData - Add snapshot filter to hide and show snapshots Signed-off-by: Akash Srivastava <akash.srivastava@openebs.io>
This commit is contained in:
+10
-1
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@@ -55,6 +56,14 @@ var (
|
||||
{Value: "hide", Label: "Hide storage", filter: render.IsPodComponent, filterPseudo: false},
|
||||
},
|
||||
}
|
||||
snapshotFilter = APITopologyOptionGroup{
|
||||
ID: "snapshot",
|
||||
Default: "hide",
|
||||
Options: []APITopologyOption{
|
||||
{Value: "show", Label: "Show snapshots", filter: nil, filterPseudo: false},
|
||||
{Value: "hide", Label: "Hide snapshots", filter: render.IsNonSnapshotComponent, filterPseudo: false},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// namespaceFilters generates a namespace selector option group based on the given namespaces
|
||||
@@ -237,7 +246,7 @@ func MakeRegistry() *Registry {
|
||||
renderer: render.PodRenderer,
|
||||
Name: "Pods",
|
||||
Rank: 3,
|
||||
Options: []APITopologyOptionGroup{storageFilter, unmanagedFilter},
|
||||
Options: []APITopologyOptionGroup{snapshotFilter, storageFilter, unmanagedFilter},
|
||||
HideIfEmpty: true,
|
||||
},
|
||||
APITopologyDesc{
|
||||
|
||||
@@ -6,10 +6,8 @@ import { enterEdge, leaveEdge } from '../actions/app-actions';
|
||||
import { encodeIdAttribute, decodeIdAttribute } from '../utils/dom-utils';
|
||||
|
||||
function isStorageComponent(id) {
|
||||
if (id === '<persistent_volume>' || id === '<storage_class>' || id === '<persistent_volume_claim>') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
const storageComponents = ['<persistent_volume>', '<storage_class>', '<persistent_volume_claim>', '<volume_snapshot>', '<volume_snapshot_data>'];
|
||||
return storageComponents.includes(id);
|
||||
}
|
||||
|
||||
// getAdjacencyClass takes id which contains information about edge as a topology
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
|
||||
"github.com/weaveworks/common/backoff"
|
||||
|
||||
snapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1"
|
||||
snapshot "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned"
|
||||
log "github.com/sirupsen/logrus"
|
||||
apiappsv1beta1 "k8s.io/api/apps/v1beta1"
|
||||
apibatchv1 "k8s.io/api/batch/v1"
|
||||
@@ -41,6 +43,8 @@ type Client interface {
|
||||
WalkPersistentVolumes(f func(PersistentVolume) error) error
|
||||
WalkPersistentVolumeClaims(f func(PersistentVolumeClaim) error) error
|
||||
WalkStorageClasses(f func(StorageClass) error) error
|
||||
WalkVolumeSnapshots(f func(VolumeSnapshot) error) error
|
||||
WalkVolumeSnapshotData(f func(VolumeSnapshotData) error) error
|
||||
|
||||
WatchPods(f func(Event, Pod))
|
||||
|
||||
@@ -53,6 +57,7 @@ type Client interface {
|
||||
type client struct {
|
||||
quit chan struct{}
|
||||
client *kubernetes.Clientset
|
||||
snapshotClient *snapshot.Clientset
|
||||
podStore cache.Store
|
||||
serviceStore cache.Store
|
||||
deploymentStore cache.Store
|
||||
@@ -65,6 +70,8 @@ type client struct {
|
||||
persistentVolumeStore cache.Store
|
||||
persistentVolumeClaimStore cache.Store
|
||||
storageClassStore cache.Store
|
||||
volumeSnapshotStore cache.Store
|
||||
volumeSnapshotDataStore cache.Store
|
||||
|
||||
podWatchesMutex sync.Mutex
|
||||
podWatches []func(Event, Pod)
|
||||
@@ -133,9 +140,15 @@ func NewClient(config ClientConfig) (Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sc, err := snapshot.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &client{
|
||||
quit: make(chan struct{}),
|
||||
client: c,
|
||||
quit: make(chan struct{}),
|
||||
client: c,
|
||||
snapshotClient: sc,
|
||||
}
|
||||
|
||||
result.podStore = NewEventStore(result.triggerPodWatches, cache.MetaNamespaceKeyFunc)
|
||||
@@ -152,6 +165,8 @@ func NewClient(config ClientConfig) (Client, error) {
|
||||
result.persistentVolumeStore = result.setupStore("persistentvolumes")
|
||||
result.persistentVolumeClaimStore = result.setupStore("persistentvolumeclaims")
|
||||
result.storageClassStore = result.setupStore("storageclasses")
|
||||
result.volumeSnapshotStore = result.setupStore("volumesnapshots")
|
||||
result.volumeSnapshotDataStore = result.setupStore("volumesnapshotdatas")
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -204,6 +219,10 @@ func (c *client) clientAndType(resource string) (rest.Interface, interface{}, er
|
||||
return c.client.BatchV1().RESTClient(), &apibatchv1.Job{}, nil
|
||||
case "statefulsets":
|
||||
return c.client.AppsV1beta1().RESTClient(), &apiappsv1beta1.StatefulSet{}, nil
|
||||
case "volumesnapshots":
|
||||
return c.snapshotClient.VolumesnapshotV1().RESTClient(), &snapshotv1.VolumeSnapshot{}, nil
|
||||
case "volumesnapshotdatas":
|
||||
return c.snapshotClient.VolumesnapshotV1().RESTClient(), &snapshotv1.VolumeSnapshotData{}, nil
|
||||
case "cronjobs":
|
||||
ok, err := c.isResourceSupported(c.client.BatchV1beta1().RESTClient().APIVersion(), resource)
|
||||
if err != nil {
|
||||
@@ -388,6 +407,26 @@ func (c *client) WalkNamespaces(f func(NamespaceResource) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) WalkVolumeSnapshots(f func(VolumeSnapshot) error) error {
|
||||
for _, m := range c.volumeSnapshotStore.List() {
|
||||
volumeSnapshot := m.(*snapshotv1.VolumeSnapshot)
|
||||
if err := f(NewVolumeSnapshot(volumeSnapshot)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) WalkVolumeSnapshotData(f func(VolumeSnapshotData) error) error {
|
||||
for _, m := range c.volumeSnapshotDataStore.List() {
|
||||
volumeSnapshotData := m.(*snapshotv1.VolumeSnapshotData)
|
||||
if err := f(NewVolumeSnapshotData(volumeSnapshotData)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) GetLogs(namespaceID, podID string, containerNames []string) (io.ReadCloser, error) {
|
||||
readClosersWithLabel := map[io.ReadCloser]string{}
|
||||
for _, container := range containerNames {
|
||||
|
||||
@@ -34,6 +34,8 @@ const (
|
||||
VolumeName = report.KubernetesVolumeName
|
||||
Provisioner = report.KubernetesProvisioner
|
||||
StorageDriver = report.KubernetesStorageDriver
|
||||
VolumeSnapshotName = report.KubernetesVolumeSnapshotName
|
||||
SnapshotData = report.KubernetesSnapshotData
|
||||
)
|
||||
|
||||
// Exposed for testing
|
||||
@@ -130,6 +132,19 @@ var (
|
||||
Provisioner: {ID: Provisioner, Label: "Provisioner", From: report.FromLatest, Priority: 3},
|
||||
}
|
||||
|
||||
VolumeSnapshotMetadataTemplates = report.MetadataTemplates{
|
||||
NodeType: {ID: NodeType, Label: "Type", From: report.FromLatest, Priority: 1},
|
||||
Namespace: {ID: Namespace, Label: "Name", From: report.FromLatest, Priority: 2},
|
||||
VolumeClaim: {ID: VolumeClaim, Label: "Persistent volume claim", From: report.FromLatest, Priority: 3},
|
||||
SnapshotData: {ID: SnapshotData, Label: "Volume snapshot data", From: report.FromLatest, Priority: 4},
|
||||
}
|
||||
|
||||
VolumeSnapshotDataMetadataTemplates = report.MetadataTemplates{
|
||||
NodeType: {ID: NodeType, Label: "Type", From: report.FromLatest, Priority: 1},
|
||||
VolumeName: {ID: VolumeName, Label: "Persistent volume", From: report.FromLatest, Priority: 2},
|
||||
VolumeSnapshotName: {ID: VolumeSnapshotName, Label: "Volume snapshot", From: report.FromLatest, Priority: 3},
|
||||
}
|
||||
|
||||
TableTemplates = report.TableTemplates{
|
||||
LabelPrefix: {
|
||||
ID: LabelPrefix,
|
||||
@@ -300,6 +315,14 @@ func (r *Reporter) Report() (report.Report, error) {
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
volumeSnapshotTopology, _, err := r.volumeSnapshotTopology()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
volumeSnapshotDataTopology, _, err := r.volumeSnapshotDataTopology()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.Pod = result.Pod.Merge(podTopology)
|
||||
result.Service = result.Service.Merge(serviceTopology)
|
||||
result.Host = result.Host.Merge(hostTopology)
|
||||
@@ -311,6 +334,8 @@ func (r *Reporter) Report() (report.Report, error) {
|
||||
result.PersistentVolume = result.PersistentVolume.Merge(persistentVolumeTopology)
|
||||
result.PersistentVolumeClaim = result.PersistentVolumeClaim.Merge(persistentVolumeClaimTopology)
|
||||
result.StorageClass = result.StorageClass.Merge(storageClassTopology)
|
||||
result.VolumeSnapshot = result.VolumeSnapshot.Merge(volumeSnapshotTopology)
|
||||
result.VolumeSnapshotData = result.VolumeSnapshotData.Merge(volumeSnapshotDataTopology)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -459,6 +484,32 @@ func (r *Reporter) storageClassTopology() (report.Topology, []StorageClass, erro
|
||||
return result, storageClasses, err
|
||||
}
|
||||
|
||||
func (r *Reporter) volumeSnapshotTopology() (report.Topology, []VolumeSnapshot, error) {
|
||||
volumeSnapshots := []VolumeSnapshot{}
|
||||
result := report.MakeTopology().
|
||||
WithMetadataTemplates(VolumeSnapshotMetadataTemplates).
|
||||
WithTableTemplates(TableTemplates)
|
||||
err := r.client.WalkVolumeSnapshots(func(p VolumeSnapshot) error {
|
||||
result.AddNode(p.GetNode(r.probeID))
|
||||
volumeSnapshots = append(volumeSnapshots, p)
|
||||
return nil
|
||||
})
|
||||
return result, volumeSnapshots, err
|
||||
}
|
||||
|
||||
func (r *Reporter) volumeSnapshotDataTopology() (report.Topology, []VolumeSnapshotData, error) {
|
||||
volumeSnapshotData := []VolumeSnapshotData{}
|
||||
result := report.MakeTopology().
|
||||
WithMetadataTemplates(VolumeSnapshotDataMetadataTemplates).
|
||||
WithTableTemplates(TableTemplates)
|
||||
err := r.client.WalkVolumeSnapshotData(func(p VolumeSnapshotData) error {
|
||||
result.AddNode(p.GetNode(r.probeID))
|
||||
volumeSnapshotData = append(volumeSnapshotData, p)
|
||||
return nil
|
||||
})
|
||||
return result, volumeSnapshotData, err
|
||||
}
|
||||
|
||||
type labelledChild interface {
|
||||
Labels() map[string]string
|
||||
AddParent(string, string)
|
||||
|
||||
@@ -164,6 +164,12 @@ func (c *mockClient) WalkPersistentVolumeClaims(f func(kubernetes.PersistentVolu
|
||||
func (c *mockClient) WalkStorageClasses(f func(kubernetes.StorageClass) error) error {
|
||||
return nil
|
||||
}
|
||||
func (c *mockClient) WalkVolumeSnapshots(f func(kubernetes.VolumeSnapshot) error) error {
|
||||
return nil
|
||||
}
|
||||
func (c *mockClient) WalkVolumeSnapshotData(f func(kubernetes.VolumeSnapshotData) error) error {
|
||||
return nil
|
||||
}
|
||||
func (*mockClient) WatchPods(func(kubernetes.Event, kubernetes.Pod)) {}
|
||||
func (c *mockClient) GetLogs(namespaceID, podName string, _ []string) (io.ReadCloser, error) {
|
||||
r, ok := c.logs[namespaceID+";"+podName]
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
snapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
// SnapshotPVName is the label key which provides PV name
|
||||
const (
|
||||
SnapshotPVName = "SnapshotMetadata-PVName"
|
||||
)
|
||||
|
||||
// VolumeSnapshot represent kubernetes VolumeSnapshot interface
|
||||
type VolumeSnapshot interface {
|
||||
Meta
|
||||
GetNode(probeID string) report.Node
|
||||
}
|
||||
|
||||
// volumeSnapshot represents kubernetes volume snapshots
|
||||
type volumeSnapshot struct {
|
||||
*snapshotv1.VolumeSnapshot
|
||||
Meta
|
||||
}
|
||||
|
||||
// NewVolumeSnapshot returns new Volume Snapshot type
|
||||
func NewVolumeSnapshot(p *snapshotv1.VolumeSnapshot) VolumeSnapshot {
|
||||
return &volumeSnapshot{VolumeSnapshot: p, Meta: meta{p.ObjectMeta}}
|
||||
}
|
||||
|
||||
// GetNode returns VolumeSnapshot as Node
|
||||
func (p *volumeSnapshot) GetNode(probeID string) report.Node {
|
||||
return p.MetaNode(report.MakeVolumeSnapshotNodeID(p.UID())).WithLatests(map[string]string{
|
||||
report.ControlProbeID: probeID,
|
||||
NodeType: "Volume Snapshot",
|
||||
VolumeClaim: p.Spec.PersistentVolumeClaimName,
|
||||
SnapshotData: p.Spec.SnapshotDataName,
|
||||
VolumeName: p.GetLabels()[SnapshotPVName],
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
snapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
// VolumeSnapshotData represent kubernetes VolumeSnapshotData interface
|
||||
type VolumeSnapshotData interface {
|
||||
Meta
|
||||
GetNode(probeID string) report.Node
|
||||
}
|
||||
|
||||
// volumeSnapshotData represents kubernetes volume snapshot data
|
||||
type volumeSnapshotData struct {
|
||||
*snapshotv1.VolumeSnapshotData
|
||||
Meta
|
||||
}
|
||||
|
||||
// NewVolumeSnapshotData returns new Volume Snapshot Data type
|
||||
func NewVolumeSnapshotData(p *snapshotv1.VolumeSnapshotData) VolumeSnapshotData {
|
||||
return &volumeSnapshotData{VolumeSnapshotData: p, Meta: meta{p.ObjectMeta}}
|
||||
}
|
||||
|
||||
// GetNode returns VolumeSnapshotData as Node
|
||||
func (p *volumeSnapshotData) GetNode(probeID string) report.Node {
|
||||
return p.MetaNode(report.MakeVolumeSnapshotDataNodeID(p.UID())).WithLatests(map[string]string{
|
||||
report.ControlProbeID: probeID,
|
||||
NodeType: "Volume Snapshot Data",
|
||||
VolumeName: p.Spec.PersistentVolumeRef.Name,
|
||||
VolumeSnapshotName: p.Spec.VolumeSnapshotRef.Name,
|
||||
})
|
||||
}
|
||||
@@ -206,6 +206,20 @@ var nodeSummaryGroupSpecs = []struct {
|
||||
Columns: []Column{},
|
||||
},
|
||||
},
|
||||
{
|
||||
topologyID: report.VolumeSnapshot,
|
||||
NodeSummaryGroup: NodeSummaryGroup{
|
||||
Label: "Volume Snapshots",
|
||||
Columns: []Column{},
|
||||
},
|
||||
},
|
||||
{
|
||||
topologyID: report.VolumeSnapshotData,
|
||||
NodeSummaryGroup: NodeSummaryGroup{
|
||||
Label: "Volume Snapshot Data",
|
||||
Columns: []Column{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func children(rc RenderContext, n report.Node) []NodeSummaryGroup {
|
||||
|
||||
@@ -84,6 +84,8 @@ var renderers = map[string]func(BasicNodeSummary, report.Node) BasicNodeSummary{
|
||||
report.PersistentVolume: persistentVolumeNodeSummary,
|
||||
report.PersistentVolumeClaim: persistentVolumeClaimNodeSummary,
|
||||
report.StorageClass: storageClassNodeSummary,
|
||||
report.VolumeSnapshot: volumeSnapshotNodeSummary,
|
||||
report.VolumeSnapshotData: volumeSnapshotDataNodeSummary,
|
||||
}
|
||||
|
||||
// For each report.Topology, map to a 'primary' API topology. This can then be used in a variety of places.
|
||||
@@ -104,6 +106,8 @@ var primaryAPITopology = map[string]string{
|
||||
report.PersistentVolume: "pods",
|
||||
report.PersistentVolumeClaim: "pods",
|
||||
report.StorageClass: "pods",
|
||||
report.VolumeSnapshot: "pods",
|
||||
report.VolumeSnapshotData: "pods",
|
||||
}
|
||||
|
||||
// MakeBasicNodeSummary returns a basic summary of a node, if
|
||||
@@ -394,6 +398,16 @@ func storageClassNodeSummary(base BasicNodeSummary, n report.Node) BasicNodeSumm
|
||||
return base
|
||||
}
|
||||
|
||||
func volumeSnapshotNodeSummary(base BasicNodeSummary, n report.Node) BasicNodeSummary {
|
||||
base = addKubernetesLabelAndRank(base, n)
|
||||
return base
|
||||
}
|
||||
|
||||
func volumeSnapshotDataNodeSummary(base BasicNodeSummary, n report.Node) BasicNodeSummary {
|
||||
base = addKubernetesLabelAndRank(base, n)
|
||||
return base
|
||||
}
|
||||
|
||||
// groupNodeSummary renders the summary for a group node. n.Topology is
|
||||
// expected to be of the form: group:container:hostname
|
||||
func groupNodeSummary(base BasicNodeSummary, r report.Report, n report.Node) BasicNodeSummary {
|
||||
|
||||
@@ -44,6 +44,8 @@ var (
|
||||
persistentVolume = node(report.PersistentVolume)
|
||||
persistentVolumeClaim = node(report.PersistentVolumeClaim)
|
||||
StorageClass = node(report.StorageClass)
|
||||
volumeSnapshot = node(report.VolumeSnapshot)
|
||||
volumeSnapshotData = node(report.VolumeSnapshotData)
|
||||
|
||||
UnknownPseudoNode1ID = render.MakePseudoNodeID(fixture.UnknownClient1IP)
|
||||
UnknownPseudoNode2ID = render.MakePseudoNodeID(fixture.UnknownClient3IP)
|
||||
@@ -282,7 +284,7 @@ var (
|
||||
kubernetes.StorageClassName: "standard",
|
||||
}).WithChild(report.MakeNode(fixture.PersistentVolumeNodeID).WithTopology(report.PersistentVolume)),
|
||||
|
||||
fixture.PersistentVolumeNodeID: persistentVolume(fixture.PersistentVolumeNodeID).
|
||||
fixture.PersistentVolumeNodeID: persistentVolume(fixture.PersistentVolumeNodeID, fixture.VolumeSnapshotNodeID).
|
||||
WithLatests(map[string]string{
|
||||
kubernetes.Name: "pongvolume",
|
||||
kubernetes.Namespace: "ping",
|
||||
@@ -291,7 +293,7 @@ var (
|
||||
kubernetes.AccessModes: "ReadWriteOnce",
|
||||
kubernetes.StorageClassName: "standard",
|
||||
kubernetes.StorageDriver: "iSCSI",
|
||||
}),
|
||||
}).WithChild(report.MakeNode(fixture.VolumeSnapshotNodeID).WithTopology(report.VolumeSnapshot)),
|
||||
|
||||
fixture.StorageClassNodeID: StorageClass(fixture.StorageClassNodeID, fixture.PersistentVolumeClaimNodeID).
|
||||
WithLatests(map[string]string{
|
||||
@@ -299,6 +301,22 @@ var (
|
||||
kubernetes.Provisioner: "pong",
|
||||
}).WithChild(report.MakeNode(fixture.PersistentVolumeClaimNodeID).WithTopology(report.PersistentVolumeClaim)),
|
||||
|
||||
fixture.VolumeSnapshotNodeID: volumeSnapshot(fixture.VolumeSnapshotNodeID, fixture.VolumeSnapshotDataNodeID).
|
||||
WithLatests(map[string]string{
|
||||
kubernetes.Name: "vs-1234",
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.VolumeClaim: "pvc-6124",
|
||||
kubernetes.SnapshotData: "vsd-1234",
|
||||
kubernetes.VolumeName: "pongvolume",
|
||||
}).WithChild(report.MakeNode(fixture.VolumeSnapshotDataNodeID).WithTopology(report.VolumeSnapshotData)),
|
||||
|
||||
fixture.VolumeSnapshotDataNodeID: volumeSnapshotData(fixture.VolumeSnapshotDataNodeID).
|
||||
WithLatests(map[string]string{
|
||||
kubernetes.Name: "vsd-1234",
|
||||
kubernetes.VolumeName: "pongvolume",
|
||||
kubernetes.VolumeSnapshotName: "vs-1234",
|
||||
}),
|
||||
|
||||
UnmanagedServerID: unmanagedServerNode,
|
||||
render.IncomingInternetID: theIncomingInternetNode(fixture.ServerPodNodeID),
|
||||
render.OutgoingInternetID: theOutgoingInternetNode,
|
||||
|
||||
@@ -138,6 +138,14 @@ func IsPodComponent(node report.Node) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsNonSnapshotComponent checks whether given node is everything but Volume Snapshot, Volume Snapshot Data
|
||||
func IsNonSnapshotComponent(node report.Node) bool {
|
||||
if node.Topology == "volume_snapshot" || node.Topology == "volume_snapshot_data" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// connected returns the node ids of nodes which have edges to/from
|
||||
// them, excluding edges to/from themselves.
|
||||
func connected(nodes report.Nodes) map[string]struct{} {
|
||||
|
||||
@@ -11,6 +11,8 @@ var KubernetesVolumesRenderer = MakeReduce(
|
||||
VolumesRenderer,
|
||||
PodToVolumeRenderer,
|
||||
PVCToStorageClassRenderer,
|
||||
PVToSnapshotRenderer,
|
||||
VolumeSnapshotRenderer,
|
||||
)
|
||||
|
||||
// VolumesRenderer is a Renderer which produces a renderable kubernetes PV & PVC
|
||||
@@ -25,13 +27,12 @@ func (v volumesRenderer) Render(rpt report.Report) Nodes {
|
||||
nodes := make(report.Nodes)
|
||||
for id, n := range rpt.PersistentVolumeClaim.Nodes {
|
||||
volume, _ := n.Latest.Lookup(kubernetes.VolumeName)
|
||||
for pvNodeID, p := range rpt.PersistentVolume.Nodes {
|
||||
for _, p := range rpt.PersistentVolume.Nodes {
|
||||
volumeName, _ := p.Latest.Lookup(kubernetes.Name)
|
||||
if volume == volumeName {
|
||||
n.Adjacency = n.Adjacency.Add(p.ID)
|
||||
n.Children = n.Children.Add(p)
|
||||
}
|
||||
nodes[pvNodeID] = p
|
||||
}
|
||||
nodes[id] = n
|
||||
}
|
||||
@@ -86,3 +87,51 @@ func (v pvcToStorageClassRenderer) Render(rpt report.Report) Nodes {
|
||||
}
|
||||
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(rpt report.Report) Nodes {
|
||||
nodes := make(report.Nodes)
|
||||
for pvNodeID, p := range rpt.PersistentVolume.Nodes {
|
||||
volumeName, _ := p.Latest.Lookup(kubernetes.Name)
|
||||
for _, volumeSnapshotNode := range rpt.VolumeSnapshot.Nodes {
|
||||
snapshotPVName, _ := volumeSnapshotNode.Latest.Lookup(kubernetes.VolumeName)
|
||||
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(rpt report.Report) Nodes {
|
||||
nodes := make(report.Nodes)
|
||||
for volumeSnapshotID, volumeSnapshotNode := range rpt.VolumeSnapshot.Nodes {
|
||||
snapshotData, _ := volumeSnapshotNode.Latest.Lookup(kubernetes.SnapshotData)
|
||||
for volumeSnapshotDataID, volumeSnapshotDataNode := range rpt.VolumeSnapshotData.Nodes {
|
||||
snapshotDataName, _ := volumeSnapshotDataNode.Latest.Lookup(kubernetes.Name)
|
||||
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}
|
||||
}
|
||||
|
||||
@@ -35,4 +35,6 @@ var (
|
||||
SelectPersistentVolume = TopologySelector(report.PersistentVolume)
|
||||
SelectPersistentVolumeClaim = TopologySelector(report.PersistentVolumeClaim)
|
||||
SelectStorageClass = TopologySelector(report.StorageClass)
|
||||
SelectVolumeSnapshot = TopologySelector(report.VolumeSnapshot)
|
||||
SelectVolumeSnapshotData = TopologySelector(report.VolumeSnapshotData)
|
||||
)
|
||||
|
||||
@@ -175,6 +175,18 @@ var (
|
||||
|
||||
// ParseStorageClassNodeID parses a storage class node ID
|
||||
ParseStorageClassNodeID = parseSingleComponentID("storage_class")
|
||||
|
||||
// MakeVolumeSnapshotNodeID produces a volume snapshot node ID from its composite parts.
|
||||
MakeVolumeSnapshotNodeID = makeSingleComponentID("volume_snapshot")
|
||||
|
||||
// ParseVolumeSnapshotNodeID parses a volume snapshot node ID
|
||||
ParseVolumeSnapshotNodeID = parseSingleComponentID("volume_snapshot")
|
||||
|
||||
// MakeVolumeSnapshotDataNodeID produces a volume snapshot data node ID from its composite parts.
|
||||
MakeVolumeSnapshotDataNodeID = makeSingleComponentID("volume_snapshot_data")
|
||||
|
||||
// ParseVolumeSnapshotDataNodeID parses a volume snapshot data node ID
|
||||
ParseVolumeSnapshotDataNodeID = parseSingleComponentID("volume_snapshot_data")
|
||||
)
|
||||
|
||||
// makeSingleComponentID makes a single-component node id encoder
|
||||
|
||||
@@ -81,6 +81,8 @@ const (
|
||||
KubernetesVolumeName = "kubernetes_volume_name"
|
||||
KubernetesProvisioner = "kubernetes_provisioner"
|
||||
KubernetesStorageDriver = "kubernetes_storage_driver"
|
||||
KubernetesVolumeSnapshotName = "kubernetes_volume_snapshot_name"
|
||||
KubernetesSnapshotData = "kuberneets_snapshot_data"
|
||||
// probe/awsecs
|
||||
ECSCluster = "ecs_cluster"
|
||||
ECSCreatedAt = "ecs_created_at"
|
||||
@@ -116,6 +118,8 @@ var commonKeys = map[string]string{
|
||||
PersistentVolume: PersistentVolume,
|
||||
PersistentVolumeClaim: PersistentVolumeClaim,
|
||||
StorageClass: StorageClass,
|
||||
VolumeSnapshot: VolumeSnapshot,
|
||||
VolumeSnapshotData: VolumeSnapshotData,
|
||||
|
||||
HostNodeID: HostNodeID,
|
||||
ControlProbeID: ControlProbeID,
|
||||
|
||||
@@ -31,6 +31,8 @@ const (
|
||||
PersistentVolume = "persistent_volume"
|
||||
PersistentVolumeClaim = "persistent_volume_claim"
|
||||
StorageClass = "storage_class"
|
||||
VolumeSnapshot = "volume_snapshot"
|
||||
VolumeSnapshotData = "volume_snapshot_data"
|
||||
|
||||
// Shapes used for different nodes
|
||||
Circle = "circle"
|
||||
@@ -72,6 +74,8 @@ var topologyNames = []string{
|
||||
PersistentVolume,
|
||||
PersistentVolumeClaim,
|
||||
StorageClass,
|
||||
VolumeSnapshot,
|
||||
VolumeSnapshotData,
|
||||
}
|
||||
|
||||
// Report is the core data type. It's produced by probes, and consumed and
|
||||
@@ -172,6 +176,12 @@ type Report struct {
|
||||
// Metadata is limited for now, more to come later.
|
||||
StorageClass Topology
|
||||
|
||||
// VolumeSnapshot represent all Kubernetes Volume Snapshots on hosts running probes.
|
||||
VolumeSnapshot Topology
|
||||
|
||||
// VolumeSnapshotData represent all Kubernetes Volume Snapshot Data on hosts running probes.
|
||||
VolumeSnapshotData Topology
|
||||
|
||||
DNS DNSRecords
|
||||
|
||||
// Sampling data for this report.
|
||||
@@ -277,6 +287,16 @@ func MakeReport() Report {
|
||||
WithShape(StorageSheet).
|
||||
WithLabel("storage class", "storage classes"),
|
||||
|
||||
VolumeSnapshot: MakeTopology().
|
||||
WithShape(DottedCylinder).
|
||||
WithTag(Camera).
|
||||
WithLabel("volume snapshot", "volume snapshots"),
|
||||
|
||||
VolumeSnapshotData: MakeTopology().
|
||||
WithShape(Cylinder).
|
||||
WithTag(Camera).
|
||||
WithLabel("volume snapshot data", "volume snapshot data"),
|
||||
|
||||
DNS: DNSRecords{},
|
||||
|
||||
Sampling: Sampling{},
|
||||
@@ -389,6 +409,10 @@ func (r *Report) topology(name string) *Topology {
|
||||
return &r.PersistentVolumeClaim
|
||||
case StorageClass:
|
||||
return &r.StorageClass
|
||||
case VolumeSnapshot:
|
||||
return &r.VolumeSnapshot
|
||||
case VolumeSnapshotData:
|
||||
return &r.VolumeSnapshotData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -107,6 +107,10 @@ var (
|
||||
PersistentVolumeClaimNodeID = report.MakePersistentVolumeClaimNodeID(PersistentVolumeClaimUID)
|
||||
StorageClassUID = "sc1234"
|
||||
StorageClassNodeID = report.MakeStorageClassNodeID(StorageClassUID)
|
||||
VolumeSnapshotUID = "vs1234"
|
||||
VolumeSnapshotNodeID = report.MakeVolumeSnapshotNodeID(VolumeSnapshotUID)
|
||||
VolumeSnapshotDataUID = "vsd1234"
|
||||
VolumeSnapshotDataNodeID = report.MakeVolumeSnapshotDataNodeID(VolumeSnapshotDataUID)
|
||||
|
||||
ClientProcess1CPUMetric = report.MakeSingletonMetric(Now.Add(-1*time.Second), 0.01)
|
||||
ClientProcess1MemoryMetric = report.MakeSingletonMetric(Now.Add(-2*time.Second), 0.02)
|
||||
@@ -396,6 +400,34 @@ var (
|
||||
WithTopology(report.StorageClass),
|
||||
},
|
||||
}.WithShape(report.StorageSheet).WithLabel("storage class", "storage classes"),
|
||||
VolumeSnapshot: report.Topology{
|
||||
Nodes: report.Nodes{
|
||||
VolumeSnapshotNodeID: report.MakeNodeWith(
|
||||
|
||||
VolumeSnapshotNodeID, map[string]string{
|
||||
kubernetes.Name: "vs-1234",
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.VolumeClaim: "pvc-6124",
|
||||
kubernetes.SnapshotData: "vsd-1234",
|
||||
kubernetes.VolumeName: "pongvolume",
|
||||
}).
|
||||
WithTopology(report.VolumeSnapshot),
|
||||
},
|
||||
}.WithShape(report.DottedCylinder).WithLabel("volume snapshot", "volume snapshots").
|
||||
WithTag(report.Camera),
|
||||
VolumeSnapshotData: report.Topology{
|
||||
Nodes: report.Nodes{
|
||||
VolumeSnapshotDataNodeID: report.MakeNodeWith(
|
||||
|
||||
VolumeSnapshotDataNodeID, map[string]string{
|
||||
kubernetes.Name: "vsd-1234",
|
||||
kubernetes.VolumeName: "pongvolume",
|
||||
kubernetes.VolumeSnapshotName: "vs-1234",
|
||||
}).
|
||||
WithTopology(report.VolumeSnapshotData),
|
||||
},
|
||||
}.WithShape(report.Cylinder).WithLabel("volume snapshot data", "volume snapshot data").
|
||||
WithTag(report.Camera),
|
||||
Sampling: report.Sampling{
|
||||
Count: 1024,
|
||||
Total: 4096,
|
||||
|
||||
Reference in New Issue
Block a user