Skip to content

Commit

Permalink
feat: Support VolumeAttachment relationships
Browse files Browse the repository at this point in the history
Signed-off-by: Justin Toh <tohjustin@hotmail.com>
  • Loading branch information
tohjustin committed Oct 14, 2021
1 parent ce3aa87 commit 623ef23
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ List of supported relationships used for discovering dependent objects:
- [Service References](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/)
- [ServiceAccount References](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/service-account-v1/)
- [StorageClass References](https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/storage-class-v1/)
- [VolumeAttachment References](https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/volume-attachment-v1/)
- Helm
- [Release References](https://helm.sh/docs/intro/using_helm/#three-big-concepts) & [Storage References](https://helm.sh/docs/topics/advanced/#storage-backends)

Expand Down
7 changes: 7 additions & 0 deletions internal/graph/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,13 @@ func ResolveDependents(m meta.RESTMapper, objects []unstructuredv1.Unstructured,
klog.V(4).Infof("Failed to get relationships for storageclass named \"%s\": %s: %s", node.Name, err)
continue
}
// Populate dependents based on VolumeAttachment relationships
case node.Group == "storage.k8s.io" && node.Kind == "VolumeAttachment":
rmap, err = getVolumeAttachmentRelationships(node)
if err != nil {
klog.V(4).Infof("Failed to get relationships for volumeattachment named \"%s\": %s: %s", node.Name, err)
continue
}
default:
continue
}
Expand Down
84 changes: 84 additions & 0 deletions internal/graph/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ const (

// Kubernetes StorageClass relationships.
RelationshipStorageClassProvisioner Relationship = "StorageClassProvisioner"

// Kubernetes VolumeAttachment relationships.
RelationshipVolumeAttachmentAttacher Relationship = "VolumeAttachmentAttacher"
RelationshipVolumeAttachmentNode Relationship = "VolumeAttachmentNode"
RelationshipVolumeAttachmentSourceVolume Relationship = "VolumeAttachmentSourceVolume"
RelationshipVolumeAttachmentSourceVolumeClaim Relationship = "VolumeAttachmentSourceVolumeClaim"
RelationshipVolumeAttachmentSourceVolumeCSIDriver Relationship = "VolumeAttachmentSourceVolumeCSIDriver"
RelationshipVolumeAttachmentSourceVolumeCSIDriverSecret Relationship = "VolumeAttachmentSourceVolumeCSIDriverSecret"
RelationshipVolumeAttachmentSourceVolumeStorageClass Relationship = "VolumeAttachmentSourceVolumeStorageClass"
)

// getClusterRoleRelationships returns a map of relationships that this
Expand Down Expand Up @@ -599,3 +608,78 @@ func getValidatingWebhookConfigurationRelationships(n *Node) (*RelationshipMap,

return &result, nil
}

// getVolumeAttachmentRelationships returns a map of relationships that this
// VolumeAttachment has with other objects, based on what was referenced in its
// manifest.
//nolint:funlen,nestif
func getVolumeAttachmentRelationships(n *Node) (*RelationshipMap, error) {
var va storagev1.VolumeAttachment
err := runtime.DefaultUnstructuredConverter.FromUnstructured(n.UnstructuredContent(), &va)
if err != nil {
return nil, err
}

var ref ObjectReference
result := newRelationshipMap()

// RelationshipVolumeAttachmentAttacher
if a := va.Spec.Attacher; len(a) > 0 {
ref = ObjectReference{Group: "storage.k8s.io", Kind: "CSIDriver", Name: a}
result.AddDependencyByKey(ref.Key(), RelationshipVolumeAttachmentAttacher)
}

// RelationshipVolumeAttachmentNode
if n := va.Spec.NodeName; len(n) > 0 {
ref = ObjectReference{Kind: "Node", Name: n}
result.AddDependencyByKey(ref.Key(), RelationshipVolumeAttachmentNode)
}

// RelationshipVolumeAttachmentSourceVolume
if pvName := va.Spec.Source.PersistentVolumeName; pvName != nil && len(*pvName) > 0 {
ref = ObjectReference{Kind: "PersistentVolume", Name: *pvName}
result.AddDependentByKey(ref.Key(), RelationshipVolumeAttachmentSourceVolume)
}

if iv := va.Spec.Source.InlineVolumeSpec; iv != nil {
// RelationshipVolumeAttachmentSourceVolumeClaim
if iv.ClaimRef != nil {
ref = ObjectReference{Kind: "PersistentVolumeClaim", Name: iv.ClaimRef.Name, Namespace: iv.ClaimRef.Namespace}
result.AddDependentByKey(ref.Key(), RelationshipVolumeAttachmentSourceVolumeClaim)
}

// RelationshipVolumeAttachmentSourceVolumeStorageClass
ref = ObjectReference{Group: "storage.k8s.io", Kind: "StorageClass", Name: iv.StorageClassName}
result.AddDependentByKey(ref.Key(), RelationshipVolumeAttachmentSourceVolumeStorageClass)

// RelationshipVolumeAttachmentSourceVolumeCSIDriver
// RelationshipVolumeAttachmentSourceVolumeCSIDriverSecret
//nolint:gocritic
switch {
case iv.PersistentVolumeSource.CSI != nil:
csi := iv.PersistentVolumeSource.CSI
if d := csi.Driver; len(d) > 0 {
ref = ObjectReference{Group: "storage.k8s.io", Kind: "CSIDriver", Name: csi.Driver}
result.AddDependentByKey(ref.Key(), RelationshipVolumeAttachmentSourceVolumeCSIDriver)
}
if ces := csi.ControllerExpandSecretRef; ces != nil {
ref = ObjectReference{Kind: "Secret", Name: ces.Name, Namespace: ces.Namespace}
result.AddDependentByKey(ref.Key(), RelationshipVolumeAttachmentSourceVolumeCSIDriverSecret)
}
if cps := csi.ControllerPublishSecretRef; cps != nil {
ref = ObjectReference{Kind: "Secret", Name: cps.Name, Namespace: cps.Namespace}
result.AddDependentByKey(ref.Key(), RelationshipVolumeAttachmentSourceVolumeCSIDriverSecret)
}
if nps := csi.NodePublishSecretRef; nps != nil {
ref = ObjectReference{Kind: "Secret", Name: nps.Name, Namespace: nps.Namespace}
result.AddDependentByKey(ref.Key(), RelationshipVolumeAttachmentSourceVolumeCSIDriverSecret)
}
if nss := csi.NodeStageSecretRef; nss != nil {
ref = ObjectReference{Kind: "Secret", Name: nss.Name, Namespace: nss.Namespace}
result.AddDependentByKey(ref.Key(), RelationshipVolumeAttachmentSourceVolumeCSIDriverSecret)
}
}
}

return &result, nil
}
31 changes: 31 additions & 0 deletions internal/printers/printers_humanreadable.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
eventsv1 "k8s.io/api/events/v1"
storagev1 "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
unstructuredv1 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -361,6 +362,34 @@ func getStatefulSetReadyStatus(u *unstructuredv1.Unstructured) (string, string,
return ready, "", nil
}

// getVolumeAttachmentReadyStatus returns the ready & status value of a
// VolumeAttachment.
func getVolumeAttachmentReadyStatus(u *unstructuredv1.Unstructured) (string, string, error) {
var va storagev1.VolumeAttachment
err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.UnstructuredContent(), &va)
if err != nil {
return "", "", err
}
var ready, status string
if va.Status.Attached {
ready = "True"
} else {
ready = "False"
}
var errTime time.Time
if err := va.Status.AttachError; err != nil {
status = err.Message
errTime = err.Time.Time
}
if err := va.Status.DetachError; err != nil {
if err.Time.After(errTime) {
status = err.Message
}
}

return ready, status, nil
}

// nodeToTableRow converts the provided node into a table row.
//nolint:gocognit,goconst
func nodeToTableRow(node *graph.Node, rset graph.RelationshipSet, namePrefix string, showGroupFn func(kind string) bool) metav1.TableRow {
Expand Down Expand Up @@ -392,6 +421,8 @@ func nodeToTableRow(node *graph.Node, rset graph.RelationshipSet, namePrefix str
ready, status, _ = getStatefulSetReadyStatus(node.Unstructured)
case node.Group == "events.k8s.io" && node.Kind == "Event":
ready, status, _ = getEventReadyStatus(node.Unstructured)
case node.Group == "storage.k8s.io" && node.Kind == "VolumeAttachment":
ready, status, _ = getVolumeAttachmentReadyStatus(node.Unstructured)
case node.Unstructured != nil:
ready, status, _ = getObjectReadyStatus(node.Unstructured)
}
Expand Down

0 comments on commit 623ef23

Please sign in to comment.