Look for pods in ownerReferences of PVC (#120427)
* Look for pods in ownerReferences of PVC * Implement for loop instead of using slices package * Add tests for getPodsForPVC function * Make PVC names consistent * Remove volumes part of the pvc owner pod * Do not store result of append in another variable * Fix lint error
This commit is contained in:
		@@ -1645,7 +1645,7 @@ func (d *PersistentVolumeClaimDescriber) Describe(namespace, name string, descri
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	pc := d.CoreV1().Pods(namespace)
 | 
						pc := d.CoreV1().Pods(namespace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pods, err := getPodsForPVC(pc, pvc.Name, describerSettings)
 | 
						pods, err := getPodsForPVC(pc, pvc, describerSettings)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1655,7 +1655,7 @@ func (d *PersistentVolumeClaimDescriber) Describe(namespace, name string, descri
 | 
				
			|||||||
	return describePersistentVolumeClaim(pvc, events, pods)
 | 
						return describePersistentVolumeClaim(pvc, events, pods)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getPodsForPVC(c corev1client.PodInterface, pvcName string, settings DescriberSettings) ([]corev1.Pod, error) {
 | 
					func getPodsForPVC(c corev1client.PodInterface, pvc *corev1.PersistentVolumeClaim, settings DescriberSettings) ([]corev1.Pod, error) {
 | 
				
			||||||
	nsPods, err := getPodsInChunks(c, metav1.ListOptions{Limit: settings.ChunkSize})
 | 
						nsPods, err := getPodsInChunks(c, metav1.ListOptions{Limit: settings.ChunkSize})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return []corev1.Pod{}, err
 | 
							return []corev1.Pod{}, err
 | 
				
			||||||
@@ -1665,12 +1665,40 @@ func getPodsForPVC(c corev1client.PodInterface, pvcName string, settings Describ
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, pod := range nsPods.Items {
 | 
						for _, pod := range nsPods.Items {
 | 
				
			||||||
		for _, volume := range pod.Spec.Volumes {
 | 
							for _, volume := range pod.Spec.Volumes {
 | 
				
			||||||
			if volume.VolumeSource.PersistentVolumeClaim != nil && volume.VolumeSource.PersistentVolumeClaim.ClaimName == pvcName {
 | 
								if volume.VolumeSource.PersistentVolumeClaim != nil && volume.VolumeSource.PersistentVolumeClaim.ClaimName == pvc.Name {
 | 
				
			||||||
				pods = append(pods, pod)
 | 
									pods = append(pods, pod)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ownersLoop:
 | 
				
			||||||
 | 
						for _, ownerRef := range pvc.ObjectMeta.OwnerReferences {
 | 
				
			||||||
 | 
							if ownerRef.Kind != "Pod" {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							podIndex := -1
 | 
				
			||||||
 | 
							for i, pod := range nsPods.Items {
 | 
				
			||||||
 | 
								if pod.UID == ownerRef.UID {
 | 
				
			||||||
 | 
									podIndex = i
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if podIndex == -1 {
 | 
				
			||||||
 | 
								// Maybe the pod has been deleted
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, pod := range pods {
 | 
				
			||||||
 | 
								if pod.UID == nsPods.Items[podIndex].UID {
 | 
				
			||||||
 | 
									// This owner pod is already recorded, look for pods between other owners
 | 
				
			||||||
 | 
									continue ownersLoop
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pods = append(pods, nsPods.Items[podIndex])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pods, nil
 | 
						return pods, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1994,6 +1994,123 @@ func TestPersistentVolumeClaimDescriber(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGetPodsForPVC(t *testing.T) {
 | 
				
			||||||
 | 
						goldClassName := "gold"
 | 
				
			||||||
 | 
						testCases := []struct {
 | 
				
			||||||
 | 
							name            string
 | 
				
			||||||
 | 
							pvc             *corev1.PersistentVolumeClaim
 | 
				
			||||||
 | 
							requiredObjects []runtime.Object
 | 
				
			||||||
 | 
							expectedPods    []string
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "pvc-unused",
 | 
				
			||||||
 | 
								pvc: &corev1.PersistentVolumeClaim{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "pvc-name"},
 | 
				
			||||||
 | 
									Spec: corev1.PersistentVolumeClaimSpec{
 | 
				
			||||||
 | 
										VolumeName:       "volume1",
 | 
				
			||||||
 | 
										StorageClassName: &goldClassName,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: corev1.PersistentVolumeClaimStatus{
 | 
				
			||||||
 | 
										Phase: corev1.ClaimBound,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedPods: []string{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "pvc-in-pods-volumes-list",
 | 
				
			||||||
 | 
								pvc: &corev1.PersistentVolumeClaim{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "pvc-name"},
 | 
				
			||||||
 | 
									Spec: corev1.PersistentVolumeClaimSpec{
 | 
				
			||||||
 | 
										VolumeName:       "volume1",
 | 
				
			||||||
 | 
										StorageClassName: &goldClassName,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: corev1.PersistentVolumeClaimStatus{
 | 
				
			||||||
 | 
										Phase: corev1.ClaimBound,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								requiredObjects: []runtime.Object{
 | 
				
			||||||
 | 
									&corev1.Pod{
 | 
				
			||||||
 | 
										ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "pod-name"},
 | 
				
			||||||
 | 
										Spec: corev1.PodSpec{
 | 
				
			||||||
 | 
											Volumes: []corev1.Volume{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Name: "volume",
 | 
				
			||||||
 | 
													VolumeSource: corev1.VolumeSource{
 | 
				
			||||||
 | 
														PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
 | 
				
			||||||
 | 
															ClaimName: "pvc-name",
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedPods: []string{"pod-name"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "pvc-owned-by-pod",
 | 
				
			||||||
 | 
								pvc: &corev1.PersistentVolumeClaim{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
										Namespace: "ns",
 | 
				
			||||||
 | 
										Name:      "pvc-name",
 | 
				
			||||||
 | 
										OwnerReferences: []metav1.OwnerReference{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Kind: "Pod",
 | 
				
			||||||
 | 
												Name: "pod-name",
 | 
				
			||||||
 | 
												UID:  "pod-uid",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Spec: corev1.PersistentVolumeClaimSpec{
 | 
				
			||||||
 | 
										VolumeName:       "volume1",
 | 
				
			||||||
 | 
										StorageClassName: &goldClassName,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: corev1.PersistentVolumeClaimStatus{
 | 
				
			||||||
 | 
										Phase: corev1.ClaimBound,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								requiredObjects: []runtime.Object{
 | 
				
			||||||
 | 
									&corev1.Pod{
 | 
				
			||||||
 | 
										ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "pod-name", UID: "pod-uid"},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedPods: []string{"pod-name"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range testCases {
 | 
				
			||||||
 | 
							t.Run(test.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								var objects []runtime.Object
 | 
				
			||||||
 | 
								objects = append(objects, test.requiredObjects...)
 | 
				
			||||||
 | 
								objects = append(objects, test.pvc)
 | 
				
			||||||
 | 
								fake := fake.NewSimpleClientset(objects...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								pods, err := getPodsForPVC(fake.CoreV1().Pods(test.pvc.ObjectMeta.Namespace), test.pvc, DescriberSettings{})
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									t.Errorf("Unexpected error for test %s: %v", test.name, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for _, expectedPod := range test.expectedPods {
 | 
				
			||||||
 | 
									foundPod := false
 | 
				
			||||||
 | 
									for _, pod := range pods {
 | 
				
			||||||
 | 
										if pod.Name == expectedPod {
 | 
				
			||||||
 | 
											foundPod = true
 | 
				
			||||||
 | 
											break
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if !foundPod {
 | 
				
			||||||
 | 
										t.Errorf("Expected pod %s, but it was not returned: %v", expectedPod, pods)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if len(test.expectedPods) != len(pods) {
 | 
				
			||||||
 | 
									t.Errorf("Expected %d pods, but got %d pods", len(test.expectedPods), len(pods))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDescribeDeployment(t *testing.T) {
 | 
					func TestDescribeDeployment(t *testing.T) {
 | 
				
			||||||
	labels := map[string]string{"k8s-app": "bar"}
 | 
						labels := map[string]string{"k8s-app": "bar"}
 | 
				
			||||||
	testCases := []struct {
 | 
						testCases := []struct {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user