Skip to content

Commit

Permalink
add persistent volume name; add volume mount name
Browse files Browse the repository at this point in the history
  • Loading branch information
yashbhutwala committed Jul 12, 2020
1 parent 2d73c89 commit 6ae04c3
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 37 deletions.
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ kubectl df-pv

### Flags

```shell
```shell script
> kubectl df-pv --help

df-pv emulates Unix style df for persistent volumes w/ ability to filter by namespace
Expand All @@ -74,6 +74,14 @@ Flags:
-v, --verbosity string log level; one of [info, debug, trace, warn, error, fatal, panic] (default "info")
```
### Other useful commands
#### enable trace logging, but output to a file
```shell script
df-pv -v trace 2> trace.log
```
## Tested
### Works on
Expand All @@ -96,19 +104,25 @@ Flags:
## TODO Features
### Yet to be completed
☒ sort-by flag
☒ exclude namespaces
☒ only show a specific colored result ("red", "yellow", "green")
### Completed
☑ `df` for all Persistent Volumes in the cluster
☑ human readable output as default (using IEC format)
&#9745; color based on usage [red: > 75% (too high); yellow: < 25% (too low); green: >= 25 and <= 75 (OK)]
&#9746; sort-by flag
&#9745; print PV name
&#9746; print PV name (right now, it prints the PVC name)
&#9746; exclude namespaces
&#9746; only show a specific colored result ("red", "yellow", "green")
&#9745; print volume mount name
## Motivation
Expand Down
79 changes: 49 additions & 30 deletions pkg/df-pv/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,17 @@ func PrintUsingGoPretty(sliceOfOutputRowPVC []*OutputRowPVC) {
// https://github.com/jedib0t/go-pretty/tree/v6.0.4/table
t := table.NewWriter()

t.AppendHeader(table.Row{"PVC", "Namespace", "Pod", "Size", "Used", "Available", "%Used", "iused", "ifree", "%iused"})
t.AppendHeader(table.Row{"Namespace", "PVC Name", "PV Name", "Pod Name", "Volume Mount Name", "Size", "Used", "Available", "%Used", "iused", "ifree", "%iused"})
hiWhiteColor := text.FgHiWhite
for _, pvcRow := range sliceOfOutputRowPVC {
percentageUsedColor := GetColorFromPercentageUsed(pvcRow.PercentageUsed)
percentageIUsedColor := GetColorFromPercentageUsed(pvcRow.PercentageIUsed)
t.AppendRow([]interface{}{
hiWhiteColor.Sprintf("%s", pvcRow.PVCName),
hiWhiteColor.Sprintf("%s", pvcRow.Namespace),
hiWhiteColor.Sprintf("%s", pvcRow.PVCName),
hiWhiteColor.Sprintf("%s", pvcRow.PVName),
hiWhiteColor.Sprintf("%s", pvcRow.PodName),
hiWhiteColor.Sprintf("%s", pvcRow.VolumeMountName),
percentageUsedColor.Sprintf("%s", ConvertQuantityValueToHumanReadableIECString(pvcRow.CapacityBytes)),
percentageUsedColor.Sprintf("%s", ConvertQuantityValueToHumanReadableIECString(pvcRow.UsedBytes)),
percentageUsedColor.Sprintf("%s", ConvertQuantityValueToHumanReadableIECString(pvcRow.AvailableBytes)),
Expand Down Expand Up @@ -321,22 +323,19 @@ func ConvertQuantityValueToHumanReadableDecimalString(quantity *resource.Quantit
// }

type OutputRowPVC struct {
PodName string `json:"podName"`
Namespace string `json:"namespace"`

PVCName string `json:"pvcName"`

AvailableBytes *resource.Quantity `json:"availableBytes"`
CapacityBytes *resource.Quantity `json:"capacityBytes"`
UsedBytes *resource.Quantity `json:"usedBytes"`
PercentageUsed float64

Namespace string `json:"namespace"`
PVCName string `json:"pvcName"`
PVName string `json:"pvName"`
PodName string `json:"podName"`
VolumeMountName string `json:"volumeMountName"`
AvailableBytes *resource.Quantity `json:"availableBytes"`
CapacityBytes *resource.Quantity `json:"capacityBytes"`
UsedBytes *resource.Quantity `json:"usedBytes"`
PercentageUsed float64
InodesFree int64 `json:"inodesFree"`
Inodes int64 `json:"inodes"`
InodesUsed int64 `json:"inodesUsed"`
PercentageIUsed float64

VolumeMountName string `json:"volumeMountName"`
}

type ServerResponseStruct struct {
Expand Down Expand Up @@ -506,13 +505,17 @@ func GetOutputRowPVCFromNodeChan(ctx context.Context, clientset *kubernetes.Clie

// for trace logging only
var nodeRespBody interface{}
_ = json.Unmarshal(responseRawArrayOfBytes, &nodeRespBody)
err = json.Unmarshal(responseRawArrayOfBytes, &nodeRespBody)
if err != nil {
return errors.Wrapf(err, "unable to unmarshal json into an interface (this really shouldn't happen)")
}
// log.Tracef("response from node: %+v\n", nodeRespBody)
jsonText, err := json.MarshalIndent(nodeRespBody, "", " ")
jsonText, err := json.Marshal(nodeRespBody)
// jsonText, err := json.MarshalIndent(nodeRespBody, "", " ")
if err != nil {
return errors.Wrapf(err, "unable to marshal json (this really shouldn't happen)")
}
log.Tracef("response from node: %s\n", jsonText)
log.Tracef("response from node: %s", jsonText)

var jsonConvertedIntoStruct ServerResponseStruct
err = json.Unmarshal(responseRawArrayOfBytes, &jsonConvertedIntoStruct)
Expand All @@ -522,7 +525,7 @@ func GetOutputRowPVCFromNodeChan(ctx context.Context, clientset *kubernetes.Clie

for _, pod := range jsonConvertedIntoStruct.Pods {
for _, vol := range pod.ListOfVolumes {
outputRowPVC := GetOutputRowPVCFromPodAndVolume(pod, vol, desiredNamespace)
outputRowPVC := GetOutputRowPVCFromPodAndVolume(ctx, clientset, pod, vol, desiredNamespace)
if nil == outputRowPVC {
log.Tracef("no pvc found for pod: '%s', vol: '%s', desiredNamespace: '%s'; continuing...", pod.PodRef.Name, vol.PvcRef.PvcName, desiredNamespace)
continue
Expand All @@ -539,7 +542,7 @@ func GetOutputRowPVCFromNodeChan(ctx context.Context, clientset *kubernetes.Clie
return nil
}

func GetOutputRowPVCFromPodAndVolume(pod *Pod, vol *Volume, desiredNamespace string) *OutputRowPVC {
func GetOutputRowPVCFromPodAndVolume(ctx context.Context, clientset *kubernetes.Clientset, pod *Pod, vol *Volume, desiredNamespace string) *OutputRowPVC {
var outputRowPVC *OutputRowPVC

if 0 < len(desiredNamespace) {
Expand All @@ -551,22 +554,28 @@ func GetOutputRowPVCFromPodAndVolume(pod *Pod, vol *Volume, desiredNamespace str
}

if 0 < len(vol.PvcRef.PvcName) {
outputRowPVC = &OutputRowPVC{
PodName: pod.PodRef.Name,
Namespace: pod.PodRef.Namespace,

PVCName: vol.PvcRef.PvcName,
AvailableBytes: resource.NewQuantity(vol.AvailableBytes, resource.BinarySI),
CapacityBytes: resource.NewQuantity(vol.CapacityBytes, resource.BinarySI),
UsedBytes: resource.NewQuantity(vol.UsedBytes, resource.BinarySI),
PercentageUsed: (float64(vol.UsedBytes) / float64(vol.CapacityBytes)) * 100.0,
namespace := pod.PodRef.Namespace
pvcName := vol.PvcRef.PvcName
pvName, _ := GetPVNameFromPVCName(ctx, clientset, namespace, pvcName)
// if err != nil {
// ctx.Err()
// return errors.Wrapf(err, "unable to get PV name from the PVC name")
// }

outputRowPVC = &OutputRowPVC{
Namespace: namespace,
PVCName: pvcName,
PVName: pvName,
PodName: pod.PodRef.Name,
VolumeMountName: vol.Name,
AvailableBytes: resource.NewQuantity(vol.AvailableBytes, resource.BinarySI),
CapacityBytes: resource.NewQuantity(vol.CapacityBytes, resource.BinarySI),
UsedBytes: resource.NewQuantity(vol.UsedBytes, resource.BinarySI),
PercentageUsed: (float64(vol.UsedBytes) / float64(vol.CapacityBytes)) * 100.0,
Inodes: vol.Inodes,
InodesFree: vol.InodesFree,
InodesUsed: vol.InodesUsed,
PercentageIUsed: (float64(vol.InodesUsed) / float64(vol.Inodes)) * 100.0,

VolumeMountName: vol.Name,
}
}
return outputRowPVC
Expand All @@ -582,6 +591,16 @@ func ListNodes(ctx context.Context, clientset *kubernetes.Clientset) (*corev1.No
return clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
}

func GetPVNameFromPVCName(ctx context.Context, clientset *kubernetes.Clientset, namespace string, pvcName string) (string, error) {
var pvName string
pvc, err := clientset.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, pvcName, metav1.GetOptions{})
if err != nil {
return pvName, err
}
pvName = pvc.Spec.VolumeName
return pvName, err
}

func KubeConfigPath() (string, error) {
log.Debugf("getting kubeconfig path based on user's home dir")
home, err := os.UserHomeDir()
Expand Down

0 comments on commit 6ae04c3

Please sign in to comment.