diff --git a/pkg/client/k8s.go b/pkg/client/k8s.go index f82a48af..a54f91f9 100644 --- a/pkg/client/k8s.go +++ b/pkg/client/k8s.go @@ -339,8 +339,8 @@ func (k K8sClient) GetCV(volName string) (*cstorv1.CStorVolume, error) { // Only one type can be returned at a time, please define the other type as '_' while calling. func (k K8sClient) GetCVs(volNames []string, rType util.ReturnType, labelSelector string, options util.MapOptions) (*cstorv1.CStorVolumeList, map[string]cstorv1.CStorVolume, error) { cVols, err := k.OpenebsCS.CstorV1().CStorVolumes("").List(context.TODO(), metav1.ListOptions{LabelSelector: labelSelector}) - if err != nil { - return nil, nil, errors.Wrapf(err, "Error while getting volumes") + if len(cVols.Items) == 0 { + return nil, nil, errors.Errorf("Error while getting volumes%v", err) } var list []cstorv1.CStorVolume if len(volNames) == 0 { @@ -404,8 +404,8 @@ func (k K8sClient) GetCVA(labelSelector string) (*cstorv1.CStorVolumeAttachment, // Only one type can be returned at a time, please define the other type as '_' while calling. func (k K8sClient) GetCVAs(rType util.ReturnType, labelSelector string, options util.MapOptions) (*cstorv1.CStorVolumeAttachmentList, map[string]cstorv1.CStorVolumeAttachment, error) { cvaList, err := k.OpenebsCS.CstorV1().CStorVolumeAttachments("").List(context.TODO(), metav1.ListOptions{LabelSelector: labelSelector}) - if err != nil { - return nil, nil, err + if len(cvaList.Items) == 0 { + return nil, nil, errors.Errorf("No CVA found for %s, %v", labelSelector, err) } if rType == util.List { return cvaList, nil, nil diff --git a/pkg/client/lvmlocalpv.go b/pkg/client/lvmlocalpv.go index 3223781c..a8221eef 100644 --- a/pkg/client/lvmlocalpv.go +++ b/pkg/client/lvmlocalpv.go @@ -45,7 +45,7 @@ func getLVMclient(kubeconfig string) (*lvmclient.Clientset, error) { // GetLVMvol returns a list or a map of LVMVolume depending upon rType & options func (k K8sClient) GetLVMvol(lVols []string, rType util.ReturnType, labelSelector string, options util.MapOptions) (*lvm.LVMVolumeList, map[string]lvm.LVMVolume, error) { // NOTE: The resource name must be plural and the API-group should be present for getting CRs - lvs, err := k.LVMCS.LocalV1alpha1().LVMVolumes(k.Ns).List(context.TODO(), v1.ListOptions{LabelSelector: labelSelector}) + lvs, err := k.LVMCS.LocalV1alpha1().LVMVolumes("").List(context.TODO(), v1.ListOptions{LabelSelector: labelSelector}) if err != nil { return nil, nil, err } diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index a4bf36d5..a6cd14f4 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -31,6 +31,8 @@ func Get(pools []string, openebsNS string, casType string) error { if f, ok := CasListMap()[casType]; ok { // if a cas-type is found, run it and return the error return f(k, pools) + } else if casType != "" { + return fmt.Errorf("cas-type %s is not supported", casType) } // 3. Call all functions & exit var separator bool diff --git a/pkg/volume/cstor.go b/pkg/volume/cstor.go index 95a81026..25aa2331 100644 --- a/pkg/volume/cstor.go +++ b/pkg/volume/cstor.go @@ -105,7 +105,7 @@ func GetCStor(c *client.K8sClient, pvList *corev1.PersistentVolumeList, openebsN accessMode := pv.Spec.AccessModes[0] rows = append(rows, metav1.TableRow{ Cells: []interface{}{ - ns, pv.Name, customStatus, storageVersion, pv.Spec.Capacity.Storage(), pv.Spec.StorageClassName, pv.Status.Phase, + ns, pv.Name, customStatus, storageVersion, util.ConvertToIBytes(pv.Spec.Capacity.Storage().String()), pv.Spec.StorageClassName, pv.Status.Phase, accessMode, attachedNode}}) } } @@ -139,8 +139,8 @@ func DescribeCstorVolume(c *client.K8sClient, vol *corev1.PersistentVolume) erro } // 5. cStor Volume Replicas - cvrInfo, err := c.GetCVRs(cstortypes.PersistentVolumeLabelKey + "=" + vol.Name) - if err != nil { + cvrInfo, _ := c.GetCVRs(cstortypes.PersistentVolumeLabelKey + "=" + vol.Name) + if len(cvrInfo.Items) == 0 { _, _ = fmt.Fprintf(os.Stderr, "failed to get cStor Volume Replicas for %s\n", vol.Name) } @@ -163,10 +163,7 @@ func DescribeCstorVolume(c *client.K8sClient, vol *corev1.PersistentVolume) erro } // Print the output for the portal status info - err = util.PrintByTemplate("volume", cstorVolInfoTemplate, volume) - if err != nil { - return err - } + _ = util.PrintByTemplate("volume", cstorVolInfoTemplate, volume) portalInfo := util.PortalInfo{ IQN: volumeInfo.Spec.Iqn, @@ -177,16 +174,13 @@ func DescribeCstorVolume(c *client.K8sClient, vol *corev1.PersistentVolume) erro } // Print the output for the portal status info - err = util.PrintByTemplate("PortalInfo", cstorPortalTemplate, portalInfo) - if err != nil { - return err - } + _ = util.PrintByTemplate("PortalInfo", cstorPortalTemplate, portalInfo) replicaCount := volumeInfo.Spec.ReplicationFactor // This case will occur only if user has manually specified zero replica. // or if none of the replicas are healthy & running if replicaCount == 0 || len(volumeInfo.Status.ReplicaStatuses) == 0 { - fmt.Printf("None of the replicas are running\n") + fmt.Printf("\nNone of the replicas are running\n") //please check the volume pod's status by running [kubectl describe pvc -l=openebs/replica --all-namespaces]\Oor try again later.") return nil } @@ -206,7 +200,7 @@ func DescribeCstorVolume(c *client.K8sClient, vol *corev1.PersistentVolume) erro util.TablePrinter(util.CstorReplicaColumnDefinations, rows, printers.PrintOptions{Wide: true}) } - cStorBackupList, _ := c.GetCVBackups(vol.Name) + cStorBackupList, _ := c.GetCVBackups(cstortypes.PersistentVolumeLabelKey + "=" + vol.Name) if cStorBackupList != nil { fmt.Printf("\nCstor Backup Details :\n" + "---------------------\n") var rows []metav1.TableRow @@ -223,7 +217,7 @@ func DescribeCstorVolume(c *client.K8sClient, vol *corev1.PersistentVolume) erro util.TablePrinter(util.CstorBackupColumnDefinations, rows, printers.PrintOptions{Wide: true}) } - cstorCompletedBackupList, _ := c.GetCVCompletedBackups(vol.Name) + cstorCompletedBackupList, _ := c.GetCVCompletedBackups(cstortypes.PersistentVolumeLabelKey + "=" + vol.Name) if cstorCompletedBackupList != nil { fmt.Printf("\nCstor Completed Backup Details :" + "\n-------------------------------\n") var rows []metav1.TableRow @@ -238,7 +232,7 @@ func DescribeCstorVolume(c *client.K8sClient, vol *corev1.PersistentVolume) erro util.TablePrinter(util.CstorCompletedBackupColumnDefinations, rows, printers.PrintOptions{Wide: true}) } - cStorRestoreList, _ := c.GetCVRestores(vol.Name) + cStorRestoreList, _ := c.GetCVRestores(cstortypes.PersistentVolumeLabelKey + "=" + vol.Name) if cStorRestoreList != nil { fmt.Printf("\nCstor Restores Details :" + "\n-----------------------\n") var rows []metav1.TableRow diff --git a/pkg/volume/cstor_test.go b/pkg/volume/cstor_test.go new file mode 100644 index 00000000..48585215 --- /dev/null +++ b/pkg/volume/cstor_test.go @@ -0,0 +1,284 @@ +/* +Copyright 2020-2021 The OpenEBS Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package volume + +import ( + openebsFakeClientset "github.com/openebs/api/v2/pkg/client/clientset/versioned/fake" + "github.com/openebs/openebsctl/pkg/client" + "github.com/openebs/openebsctl/pkg/util" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" + "reflect" + "testing" +) + +func TestDescribeCstorVolume(t *testing.T) { + cvRep := cv1 + cvRep.Spec.ReplicationFactor = 0 + cvRep.Status.ReplicaStatuses = nil + type args struct { + c *client.K8sClient + vol *corev1.PersistentVolume + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "All Valid Values", + args: args{ + c: &client.K8sClient{ + Ns: "cstor", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cv2, &cva1, &cva2, &cvc1, &cvc2, &cvr1, &cvr2, &cvr3, &cvr4, &cbkp, &ccbkp, &crestore), + }, + vol: &cstorPV1, + }, + wantErr: false, + }, + { + name: "All Valid Values with CV absent", + args: args{ + c: &client.K8sClient{ + Ns: "cstor", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv2, &cva1, &cva2, &cvc1, &cvc2, &cvr1, &cvr2, &cvr3, &cvr4, &cbkp, &ccbkp, &crestore), + }, + vol: &cstorPV1, + }, + wantErr: true, + }, + { + name: "All Valid Values with CVC absent", + args: args{ + c: &client.K8sClient{ + Ns: "cstor", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cv2, &cva1, &cva2, &cvc2, &cvr1, &cvr2, &cvr3, &cvr4, &cbkp, &ccbkp, &crestore), + }, + vol: &cstorPV1, + }, + wantErr: true, + }, + { + name: "All Valid Values with CVA absent", + args: args{ + c: &client.K8sClient{ + Ns: "cstor", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cv2, &cva2,&cvc1, &cvc2, &cvr1, &cvr2, &cvr3, &cvr4, &cbkp, &ccbkp, &crestore), + }, + vol: &cstorPV1, + }, + wantErr: false, + }, + { + name: "All Valid Values with CVRs absent", + args: args{ + c: &client.K8sClient{ + Ns: "cstor", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cv2, &cva2,&cvc1, &cvc2,&cvr4, &cbkp, &ccbkp, &crestore), + }, + vol: &cstorPV1, + }, + wantErr: false, + }, + { + name: "All Valid Values with CVR count as 0", + args: args{ + c: &client.K8sClient{ + Ns: "cstor", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cvRep, &cv2, &cva2,&cvc1, &cvc2,&cvr4, &cbkp, &ccbkp, &crestore), + }, + vol: &cstorPV1, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := DescribeCstorVolume(tt.args.c, tt.args.vol); (err != nil) != tt.wantErr { + t.Errorf("DescribeCstorVolume() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestGetCStor(t *testing.T) { + type args struct { + c *client.K8sClient + pvList *corev1.PersistentVolumeList + openebsNS string + } + tests := []struct { + name string + args args + want []metav1.TableRow + wantErr bool + }{ + { + name: "Test with all valid resources present.", + args: args{ + c: &client.K8sClient{ + Ns: "", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cv2, &cva1, &cva2, &cvc1, &cvc2, &cvr1, &cvr2, &cvr3, &cvr4, &cbkp, &ccbkp, &crestore), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{cstorPV1, cstorPV2}}, + openebsNS: "cstor", + }, + want: []metav1.TableRow{{Cells: []interface{}{ + "cstor", "pvc-1", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-1"}, + }, {Cells: []interface{}{ + "cstor", "pvc-2", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-2"}, + }}, + wantErr: false, + }, + { + name: "Test with one of the required cv not present", + args: args{ + c: &client.K8sClient{ + Ns: "", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cva1, &cva2, &cvc1, &cvc2, &cvr1, &cvr2, &cvr3, &cvr4, &cbkp, &ccbkp, &crestore), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{cstorPV1, cstorPV2}}, + openebsNS: "cstor", + }, + want: []metav1.TableRow{{Cells: []interface{}{ + "cstor", "pvc-1", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-1"}, + }}, + wantErr: false, + }, + { + name: "Test with one of the required cva not present, i.e node cannot be determined", + args: args{ + c: &client.K8sClient{ + Ns: "", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cv2, &cva1, &cvc1, &cvc2, &cvr1, &cvr2, &cvr3, &cvr4, &cbkp, &ccbkp, &crestore), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{cstorPV1, cstorPV2}}, + openebsNS: "cstor", + }, + want: []metav1.TableRow{{Cells: []interface{}{ + "cstor", "pvc-1", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-1"}, + }, {Cells: []interface{}{ + "cstor", "pvc-2", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, ""}, + }}, + wantErr: false, + }, + { + name: "Test with one of the required cvc not present, i.e nothing should break in code", + args: args{ + c: &client.K8sClient{ + Ns: "", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cv2, &cva1, &cva2, &cvc1, &cvr1, &cvr2, &cvr3, &cvr4, &cbkp, &ccbkp, &crestore), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{cstorPV1, cstorPV2}}, + openebsNS: "cstor", + }, + want: []metav1.TableRow{{Cells: []interface{}{ + "cstor", "pvc-1", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-1"}, + }, {Cells: []interface{}{ + "cstor", "pvc-2", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-2"}, + }}, + wantErr: false, + }, + { + name: "Test with two of the required cvrs not present, i.e nothing should break in code", + args: args{ + c: &client.K8sClient{ + Ns: "", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cv2, &cva1, &cva2, &cvc1, &cvr3, &cvr4, &cbkp, &ccbkp, &crestore), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{cstorPV1, cstorPV2}}, + openebsNS: "cstor", + }, + want: []metav1.TableRow{{Cells: []interface{}{ + "cstor", "pvc-1", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-1"}, + }, {Cells: []interface{}{ + "cstor", "pvc-2", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-2"}, + }}, + wantErr: false, + }, + { + name: "Test with backup and restore crs not present, i.e nothing should break in code", + args: args{ + c: &client.K8sClient{ + Ns: "", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1, &cv2, &cva1, &cva2, &cvc1, &cvr3, &cvr4), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{cstorPV1, cstorPV2}}, + openebsNS: "cstor", + }, + want: []metav1.TableRow{{Cells: []interface{}{ + "cstor", "pvc-1", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-1"}, + }, {Cells: []interface{}{ + "cstor", "pvc-2", util.Healthy, "2.11.0", "4.0 GiB", "cstor-sc", corev1.VolumeBound, corev1.ReadWriteOnce, "node-2"}, + }}, + wantErr: false, + }, + { + name: "Test with none of the underlying cstor crs", + args: args{ + c: &client.K8sClient{ + Ns: "", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{cstorPV1}}, + openebsNS: "cstor", + }, + want: nil, + wantErr: true, + }, + { + name: "Test with none of the underlying cvas are present", + args: args{ + c: &client.K8sClient{ + Ns: "", + K8sCS: fake.NewSimpleClientset(&cstorPV1, &cstorPV2, &cstorPVC1, &cstorPVC2, &nsCstor), + OpenebsCS: openebsFakeClientset.NewSimpleClientset(&cv1), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{cstorPV1}}, + openebsNS: "cstor", + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GetCStor(tt.args.c, tt.args.pvList, tt.args.openebsNS) + if (err != nil) != tt.wantErr { + t.Errorf("GetCStor() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetCStor() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/volume/jiva_test.go b/pkg/volume/jiva_test.go new file mode 100644 index 00000000..7549dad0 --- /dev/null +++ b/pkg/volume/jiva_test.go @@ -0,0 +1,74 @@ +/* +Copyright 2020-2021 The OpenEBS Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package volume + +import ( + "github.com/openebs/openebsctl/pkg/client" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "reflect" + "testing" +) + +func TestDescribeJivaVolume(t *testing.T) { + type args struct { + c *client.K8sClient + vol *corev1.PersistentVolume + } + tests := []struct { + name string + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := DescribeJivaVolume(tt.args.c, tt.args.vol); (err != nil) != tt.wantErr { + t.Errorf("DescribeJivaVolume() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestGetJiva(t *testing.T) { + type args struct { + c *client.K8sClient + pvList *corev1.PersistentVolumeList + openebsNS string + } + tests := []struct { + name string + args args + want []metav1.TableRow + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GetJiva(tt.args.c, tt.args.pvList, tt.args.openebsNS) + if (err != nil) != tt.wantErr { + t.Errorf("GetJiva() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetJiva() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/volume/lvmlocalpv.go b/pkg/volume/lvmlocalpv.go index 70fa76fe..7795a310 100644 --- a/pkg/volume/lvmlocalpv.go +++ b/pkg/volume/lvmlocalpv.go @@ -57,7 +57,7 @@ func GetLVMLocalPV(c *client.K8sClient, pvList *corev1.PersistentVolumeList, ope attachedNode = lvmVol.Spec.OwnerNodeID rows = append(rows, metav1.TableRow{ Cells: []interface{}{ - ns, pv.Name, customStatus, version, pv.Spec.Capacity.Storage().String(), pv.Spec.StorageClassName, pv.Status.Phase, + ns, pv.Name, customStatus, version, util.ConvertToIBytes(pv.Spec.Capacity.Storage().String()), pv.Spec.StorageClassName, pv.Status.Phase, accessMode, attachedNode}}) } } diff --git a/pkg/volume/lvmlocalpv_test.go b/pkg/volume/lvmlocalpv_test.go index f3b7ac9c..e5b44123 100644 --- a/pkg/volume/lvmlocalpv_test.go +++ b/pkg/volume/lvmlocalpv_test.go @@ -17,99 +17,18 @@ package volume import ( "fmt" - "reflect" - "testing" - "time" - - lvm "github.com/openebs/lvm-localpv/pkg/apis/openebs.io/lvm/v1alpha1" "github.com/openebs/lvm-localpv/pkg/generated/clientset/internalclientset/fake" fakelvm "github.com/openebs/lvm-localpv/pkg/generated/clientset/internalclientset/typed/lvm/v1alpha1/fake" "github.com/openebs/openebsctl/pkg/client" - "github.com/openebs/openebsctl/pkg/util" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" k8sfake "k8s.io/client-go/kubernetes/fake" k8stest "k8s.io/client-go/testing" + "reflect" + "testing" ) -var lvmVol1 = lvm.LVMVolume{ - TypeMeta: metav1.TypeMeta{ - Kind: "LVMVolume", - APIVersion: "lvm.openebs.io/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "pvc-1", - Namespace: "lvmlocalpv", - CreationTimestamp: metav1.Time{Time: time.Now()}, - Labels: map[string]string{}, - Annotations: map[string]string{}, - OwnerReferences: nil, - Finalizers: nil, - }, - Spec: lvm.VolumeInfo{ - OwnerNodeID: "node1", - VolGroup: "lvmpv", - VgPattern: "vg1*", - Capacity: "4Gi", - Shared: "NotShared", - ThinProvision: "No", - }, - Status: lvm.VolStatus{ - State: "Ready", - Error: nil, - }, -} - -var lvmPV1 = corev1.PersistentVolume{ - TypeMeta: metav1.TypeMeta{ - Kind: "PersistentVolume", - APIVersion: "core/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "pvc-1", - Labels: map[string]string{}, - Annotations: map[string]string{}, - }, - Spec: corev1.PersistentVolumeSpec{ - // 4GiB - Capacity: corev1.ResourceList{corev1.ResourceStorage: fourGigiByte}, - PersistentVolumeSource: corev1.PersistentVolumeSource{CSI: &corev1.CSIPersistentVolumeSource{Driver: util.LocalPVLVMCSIDriver}}, - AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce}, - ClaimRef: nil, - PersistentVolumeReclaimPolicy: corev1.PersistentVolumeReclaimDelete, - StorageClassName: "lvm-sc-1", - VolumeMode: &blockFS, - NodeAffinity: &corev1.VolumeNodeAffinity{ - Required: &corev1.NodeSelector{NodeSelectorTerms: []corev1.NodeSelectorTerm{ - {MatchExpressions: []corev1.NodeSelectorRequirement{ - {Key: "kubernetes.io/hostname", Operator: corev1.NodeSelectorOpIn, Values: []string{"node2"}}, - }}, - }}, - }, - }, - Status: corev1.PersistentVolumeStatus{ - Phase: corev1.VolumeBound, - Message: "Storage class not found", - Reason: "K8s API was down", - }, -} - -var localpvCSICtrlSTS = appsv1.StatefulSet{ - TypeMeta: metav1.TypeMeta{ - Kind: "StatefulSet", - APIVersion: "apps/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "fake-LVM-CSI", - Namespace: "lvm", - Labels: map[string]string{ - "openebs.io/version": "1.9.0", - "openebs.io/component-name": "openebs-lvm-controller"}, - }, -} - func TestGetLVMLocalPV(t *testing.T) { type args struct { c *client.K8sClient @@ -153,10 +72,24 @@ func TestGetLVMLocalPV(t *testing.T) { wantErr: false, want: []metav1.TableRow{ { - Cells: []interface{}{"lvmlocalpv", "pvc-1", "Ready", "1.9.0", "4Gi", "lvm-sc-1", corev1.VolumeBound, corev1.ReadWriteOnce, "node1"}, + Cells: []interface{}{"lvmlocalpv", "pvc-1", "Ready", "1.9.0", "4.0 GiB", "lvm-sc-1", corev1.VolumeBound, corev1.ReadWriteOnce, "node1"}, }, }, }, + { + name: "only one lvm volume presentm with lvmvol absent", + args: args{ + c: &client.K8sClient{ + Ns: "lvmlocalpv", + K8sCS: k8sfake.NewSimpleClientset(&localpvCSICtrlSTS), + LVMCS: fake.NewSimpleClientset(), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{lvmPV1}}, + openebsNS: "lvmlocalpv", + }, + wantErr: false, + want: nil, + }, { name: "only one lvm volume present, namespace conflicts", args: args{ @@ -166,7 +99,7 @@ func TestGetLVMLocalPV(t *testing.T) { LVMCS: fake.NewSimpleClientset(&lvmVol1), }, pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{jivaPV1, lvmPV1}}, - openebsNS: "lvmlocalpv", + openebsNS: "lvmlocalpvXYZ", }, wantErr: false, want: nil, @@ -191,8 +124,8 @@ func TestGetLVMLocalPV(t *testing.T) { t.Errorf("GetLVMLocalPV() returned %d elements, wanted %d elements", gotLen, expectedLen) } for i, gotLine := range got { - if len(gotLine.Cells) != len(tt.want[i].Cells) { - t.Errorf("Line#%d in output had %d elements, wanted %d elements", (i + 1), len(gotLine.Cells), len(tt.want[i].Cells)) + if len(gotLine.Cells) != len(tt.want[i].Cells){ + t.Errorf("Line#%d in output had %d elements, wanted %d elements", i+1, len(gotLine.Cells), len(tt.want[i].Cells)) } if !reflect.DeepEqual(tt.want[i].Cells, gotLine.Cells) { t.Errorf("GetLVMLocalPV() line#%d got = %v, want %v", i+1, got, tt.want) diff --git a/pkg/volume/testdata_test.go b/pkg/volume/testdata_test.go index 3a4f2d05..3cbffd71 100644 --- a/pkg/volume/testdata_test.go +++ b/pkg/volume/testdata_test.go @@ -17,46 +17,571 @@ limitations under the License. package volume import ( + v1 "github.com/openebs/api/v2/pkg/apis/cstor/v1" + cstortypes "github.com/openebs/api/v2/pkg/apis/types" + lvm "github.com/openebs/lvm-localpv/pkg/apis/openebs.io/lvm/v1alpha1" "github.com/openebs/openebsctl/pkg/util" + zfs "github.com/openebs/zfs-localpv/pkg/apis/openebs.io/zfs/v1" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "time" ) + // Some storage sizes for PVs var ( fourGigiByte = resource.MustParse("4Gi") //fiveGigaByte = resource.MustParse("5G") //fiveGigaBit = resource.MustParse("5G") //fiveGigiBit = resource.MustParse("5Gi") - blockFS = corev1.PersistentVolumeBlock + blockFS = corev1.PersistentVolumeBlock ) + +/**************** +* CSTOR +****************/ + +var nsCstor = corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cstor", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{}, + Finalizers: []string{}, + }, + Spec: corev1.NamespaceSpec{Finalizers: []corev1.FinalizerName{corev1.FinalizerKubernetes}}, +} + +var cv1 = v1.CStorVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Spec: v1.CStorVolumeSpec{ + Capacity: fourGigiByte, + TargetIP: "10.2.2.2", + TargetPort: "3002", + Iqn: "pvc1-some-fake-iqn", + TargetPortal: "10.2.2.2:3002", + ReplicationFactor: 3, + ConsistencyFactor: 0, + DesiredReplicationFactor: 0, + ReplicaDetails: v1.CStorVolumeReplicaDetails{KnownReplicas: map[v1.ReplicaID]string{ + "some-id-1": "pvc-1-rep-1", "some-id-2": "pvc-1-rep-2", "some-id-3": "pvc-1-rep-3"}, + }, + }, + Status: v1.CStorVolumeStatus{ + Phase: util.Healthy, + ReplicaStatuses: []v1.ReplicaStatus{{ID: "some-id-1", Mode: "Healthy"}, {ID: "some-id-2", Mode: "Healthy"}, {ID: "some-id-3", Mode: "Healthy"}}, + Capacity: fourGigiByte, + ReplicaDetails: v1.CStorVolumeReplicaDetails{KnownReplicas: map[v1.ReplicaID]string{ + "some-id-1": "pvc-1-rep-1", "some-id-2": "pvc-1-rep-2", "some-id-3": "pvc-1-rep-3"}, + }, + }, + VersionDetails: v1.VersionDetails{ + AutoUpgrade: false, + Desired: "2.11.0", + Status: v1.VersionStatus{ + DependentsUpgraded: true, + Current: "2.11.0", + LastUpdateTime: metav1.Time{}, + }, + }, +} + +var cv2 = v1.CStorVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-2", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Spec: v1.CStorVolumeSpec{ + Capacity: fourGigiByte, + TargetIP: "10.2.2.2", + TargetPort: "3002", + Iqn: "pvc1-some-fake-iqn", + TargetPortal: "10.2.2.2:3002", + ReplicationFactor: 3, + ConsistencyFactor: 0, + DesiredReplicationFactor: 0, + ReplicaDetails: v1.CStorVolumeReplicaDetails{KnownReplicas: map[v1.ReplicaID]string{ + "some-id-1": "pvc-2-rep-1"}, + }, + }, + Status: v1.CStorVolumeStatus{ + Phase: util.Healthy, + ReplicaStatuses: []v1.ReplicaStatus{{ID: "some-id-1", Mode: "Healthy"}}, + Capacity: fourGigiByte, + ReplicaDetails: v1.CStorVolumeReplicaDetails{KnownReplicas: map[v1.ReplicaID]string{ + "some-id-1": "pvc-2-rep-1"}, + }, + }, + VersionDetails: v1.VersionDetails{ + AutoUpgrade: false, + Desired: "2.11.0", + Status: v1.VersionStatus{ + DependentsUpgraded: true, + Current: "2.11.0", + LastUpdateTime: metav1.Time{}, + }, + }, +} + +var cvc1 = v1.CStorVolumeConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Spec: v1.CStorVolumeConfigSpec{Provision: v1.VolumeProvision{ + Capacity: corev1.ResourceList{corev1.ResourceStorage: fourGigiByte}, + ReplicaCount: 3, + }}, + Publish: v1.CStorVolumeConfigPublish{}, + Status: v1.CStorVolumeConfigStatus{PoolInfo: []string{"pool-1", "pool-2", "pool-3"}}, + VersionDetails: v1.VersionDetails{ + AutoUpgrade: false, + Desired: "2.11.0", + Status: v1.VersionStatus{Current: "2.11.0"}, + }, +} + +var cvc2 = v1.CStorVolumeConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-2", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Spec: v1.CStorVolumeConfigSpec{Provision: v1.VolumeProvision{ + Capacity: corev1.ResourceList{corev1.ResourceStorage: fourGigiByte}, + ReplicaCount: 3, + }}, + Publish: v1.CStorVolumeConfigPublish{}, + Status: v1.CStorVolumeConfigStatus{PoolInfo: []string{"pool-1"}}, + VersionDetails: v1.VersionDetails{ + AutoUpgrade: false, + Desired: "2.11.0", + Status: v1.VersionStatus{Current: "2.11.0"}, + }, +} + +var cva1 = v1.CStorVolumeAttachment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1-cva", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{"Volname": "pvc-1", "nodeID": "node-1"}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Spec: v1.CStorVolumeAttachmentSpec{Volume: v1.VolumeInfo{OwnerNodeID: "node-1"}}, +} + +var cva2 = v1.CStorVolumeAttachment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-2-cva", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{"Volname": "pvc-2", "nodeID": "node-2"}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Spec: v1.CStorVolumeAttachmentSpec{Volume: v1.VolumeInfo{OwnerNodeID: "node-2"}}, +} + +var cvr1 = v1.CStorVolumeReplica{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1-rep-1", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-1"}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Status: v1.CStorVolumeReplicaStatus{ + Capacity: v1.CStorVolumeReplicaCapacityDetails{ + Total: "4Gi", + Used: "70Mi", + }, + Phase: v1.CVRStatusOnline, + }, +} + +var cvr2 = v1.CStorVolumeReplica{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1-rep-2", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-1"}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Status: v1.CStorVolumeReplicaStatus{ + Capacity: v1.CStorVolumeReplicaCapacityDetails{ + Total: "4Gi", + Used: "70Mi", + }, + Phase: v1.CVRStatusOnline, + }, +} + +var cvr3 = v1.CStorVolumeReplica{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1-rep-3", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-1"}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Status: v1.CStorVolumeReplicaStatus{ + Capacity: v1.CStorVolumeReplicaCapacityDetails{ + Total: "4Gi", + Used: "70Mi", + }, + Phase: v1.CVRStatusOnline, + }, +} + +var cvr4 = v1.CStorVolumeReplica{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-2-rep-1", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-2"}, + Finalizers: []string{}, + Namespace: "cstor", + }, + Status: v1.CStorVolumeReplicaStatus{ + Capacity: v1.CStorVolumeReplicaCapacityDetails{ + Total: "4Gi", + Used: "70Mi", + }, + Phase: v1.CVRStatusOnline, + }, +} + +var ( + cstorScName = "cstor-sc" + cstorVolumeMode = corev1.PersistentVolumeFilesystem + cstorPVC1 = corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cstor-pvc-1", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-2"}, + Finalizers: []string{}, + Namespace: "default", + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, + Resources: corev1.ResourceRequirements{Requests: map[corev1.ResourceName]resource.Quantity{corev1.ResourceStorage: fourGigiByte}}, + VolumeName: "pvc-1", + StorageClassName: &cstorScName, + VolumeMode: &cstorVolumeMode, + }, + Status: corev1.PersistentVolumeClaimStatus{Phase: corev1.ClaimBound, Capacity: corev1.ResourceList{corev1.ResourceStorage: fourGigiByte}}, + } +) + +var ( + cstorPVC2 = corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cstor-pvc-2", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-2"}, + Finalizers: []string{}, + Namespace: "default", + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, + Resources: corev1.ResourceRequirements{Requests: map[corev1.ResourceName]resource.Quantity{corev1.ResourceStorage: fourGigiByte}}, + VolumeName: "pvc-2", + StorageClassName: &cstorScName, + VolumeMode: &cstorVolumeMode, + }, + Status: corev1.PersistentVolumeClaimStatus{Phase: corev1.ClaimBound, Capacity: corev1.ResourceList{corev1.ResourceStorage: fourGigiByte}}, + } +) + +var ( + cstorPV1 = corev1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-1"}, + Finalizers: []string{}, + }, + Spec: corev1.PersistentVolumeSpec{ + Capacity: corev1.ResourceList{corev1.ResourceStorage: fourGigiByte}, + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, + ClaimRef: &corev1.ObjectReference{ + Namespace: "default", + Name: "cstor-pvc-1", + }, + PersistentVolumeReclaimPolicy: "Retain", + StorageClassName: cstorScName, + VolumeMode: &cstorVolumeMode, + PersistentVolumeSource: corev1.PersistentVolumeSource{CSI: &corev1.CSIPersistentVolumeSource{ + Driver: "cstor.csi.openebs.io", + }}, + }, + Status: corev1.PersistentVolumeStatus{Phase: corev1.VolumeBound}, + } +) + +var ( + cstorPV2 = corev1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-2", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-2"}, + Finalizers: []string{}, + }, + Spec: corev1.PersistentVolumeSpec{ + Capacity: corev1.ResourceList{corev1.ResourceStorage: fourGigiByte}, + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, + ClaimRef: &corev1.ObjectReference{ + Namespace: "default", + Name: "cstor-pvc-2", + }, + PersistentVolumeReclaimPolicy: "Retain", + StorageClassName: cstorScName, + VolumeMode: &cstorVolumeMode, + PersistentVolumeSource: corev1.PersistentVolumeSource{CSI: &corev1.CSIPersistentVolumeSource{ + Driver: "cstor.csi.openebs.io", + }}, + }, + Status: corev1.PersistentVolumeStatus{Phase: corev1.VolumeBound}, + } +) + +var cbkp = v1.CStorBackup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "bkp-name", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-1"}, + Finalizers: []string{}, + }, + Spec: v1.CStorBackupSpec{ + BackupName: "bkp-name", + VolumeName: "pvc-1", + SnapName: "snap-name", + PrevSnapName: "prev-snap-name", + BackupDest: "10.2.2.7", + LocalSnap: true, + }, + Status: v1.BKPCStorStatusDone, +} + +var ccbkp = v1.CStorCompletedBackup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "completed-bkp-name", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-1"}, + Finalizers: []string{}, + }, + Spec: v1.CStorCompletedBackupSpec{ + BackupName: "completed-bkp-name", + VolumeName: "pvc-1", + SecondLastSnapName: "secondlast-snapshot-name", + LastSnapName: "last-snapshot-name", + }, +} + +var crestore = v1.CStorRestore{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restore-name", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{cstortypes.PersistentVolumeLabelKey: "pvc-1"}, + Finalizers: []string{}, + }, + Spec: v1.CStorRestoreSpec{ + RestoreName: "restore-name", + VolumeName: "pvc-1", + RestoreSrc: "10.2.2.7", + MaxRetryCount: 3, + RetryCount: 2, + StorageClass: "cstor-sc", + Size: fourGigiByte, + Local: true, + }, +} + +/**************** +* LVM LOCAL PV +****************/ + +var lvmVol1 = lvm.LVMVolume{ + TypeMeta: metav1.TypeMeta{ + Kind: "LVMVolume", + APIVersion: "lvm.openebs.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1", + Namespace: "lvmlocalpv", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{}, + Annotations: map[string]string{}, + OwnerReferences: nil, + Finalizers: nil, + }, + Spec: lvm.VolumeInfo{ + OwnerNodeID: "node1", + VolGroup: "lvmpv", + VgPattern: "vg1*", + Capacity: "4Gi", + Shared: "NotShared", + ThinProvision: "No", + }, + Status: lvm.VolStatus{ + State: "Ready", + Error: nil, + }, +} + +var lvmPV1 = corev1.PersistentVolume{ + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolume", + APIVersion: "core/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1", + Labels: map[string]string{}, + Annotations: map[string]string{}, + }, + Spec: corev1.PersistentVolumeSpec{ + // 4GiB + Capacity: corev1.ResourceList{corev1.ResourceStorage: fourGigiByte}, + PersistentVolumeSource: corev1.PersistentVolumeSource{CSI: &corev1.CSIPersistentVolumeSource{Driver: util.LocalPVLVMCSIDriver}}, + AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce}, + ClaimRef: nil, + PersistentVolumeReclaimPolicy: corev1.PersistentVolumeReclaimDelete, + StorageClassName: "lvm-sc-1", + VolumeMode: &blockFS, + NodeAffinity: &corev1.VolumeNodeAffinity{ + Required: &corev1.NodeSelector{NodeSelectorTerms: []corev1.NodeSelectorTerm{ + {MatchExpressions: []corev1.NodeSelectorRequirement{ + {Key: "kubernetes.io/hostname", Operator: corev1.NodeSelectorOpIn, Values: []string{"node2"}}, + }}, + }}, + }, + }, + Status: corev1.PersistentVolumeStatus{ + Phase: corev1.VolumeBound, + Message: "Storage class not found", + Reason: "K8s API was down", + }, +} + +var localpvCSICtrlSTS = appsv1.StatefulSet{ + TypeMeta: metav1.TypeMeta{ + Kind: "StatefulSet", + APIVersion: "apps/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-LVM-CSI", + Namespace: "lvm", + Labels: map[string]string{ + "openebs.io/version": "1.9.0", + "openebs.io/component-name": "openebs-lvm-controller"}, + }, +} + +/**************** +* ZFS LOCAL PV +****************/ + +var zfsVol1 = zfs.ZFSVolume{ + TypeMeta: metav1.TypeMeta{ + Kind: "ZFSVolume", + APIVersion: "zfs.openebs.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1", + Namespace: "zfslocalpv", + CreationTimestamp: metav1.Time{Time: time.Now()}, + Labels: map[string]string{"kubernetes.io/nodename": "node1"}, + Annotations: map[string]string{}, + OwnerReferences: nil, + Finalizers: nil, + }, + Spec: zfs.VolumeInfo{ + OwnerNodeID: "node1", + PoolName: "zfspv", + Capacity: "4Gi", + Shared: "NotShared", + ThinProvision: "No", + }, + Status: zfs.VolStatus{ + State: "Ready", + }, +} + +var zfsPV1 = corev1.PersistentVolume{ + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolume", + APIVersion: "core/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-1", + Labels: map[string]string{}, + Annotations: map[string]string{}, + }, + Spec: corev1.PersistentVolumeSpec{ + // 4GiB + Capacity: corev1.ResourceList{corev1.ResourceStorage: fourGigiByte}, + PersistentVolumeSource: corev1.PersistentVolumeSource{CSI: &corev1.CSIPersistentVolumeSource{Driver: util.ZFSCSIDriver}}, + AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce}, + ClaimRef: nil, + PersistentVolumeReclaimPolicy: corev1.PersistentVolumeReclaimDelete, + StorageClassName: "zfs-sc-1", + VolumeMode: &blockFS, + NodeAffinity: &corev1.VolumeNodeAffinity{ + Required: &corev1.NodeSelector{NodeSelectorTerms: []corev1.NodeSelectorTerm{ + {MatchExpressions: []corev1.NodeSelectorRequirement{ + {Key: "kubernetes.io/hostname", Operator: corev1.NodeSelectorOpIn, Values: []string{"node2"}}, + }}, + }}, + }, + }, + Status: corev1.PersistentVolumeStatus{ + Phase: corev1.VolumeBound, + Message: "Storage class not found", + Reason: "K8s API was down", + }, +} + +var localpvzfsCSICtrlSTS = appsv1.StatefulSet{ + TypeMeta: metav1.TypeMeta{ + Kind: "StatefulSet", + APIVersion: "apps/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-ZFS-CSI", + Namespace: "zfslocalpv", + Labels: map[string]string{ + "openebs.io/version": "1.9.0", + "openebs.io/component-name": "openebs-zfs-controller"}, + }, +} + +/**************** +* JIVA +****************/ + //var nsJiva = corev1.Namespace{ // ObjectMeta: metav1.ObjectMeta{ // Name: "jiva", -// CreationTimestamp: metav1.Time{time.Now()}, -// Labels: map[string]string{}, -// Finalizers: []string{}, -// }, -// Spec: corev1.NamespaceSpec{Finalizers: []corev1.FinalizerName{corev1.FinalizerKubernetes}}, -//} -//var nsCstor = corev1.Namespace{ -// ObjectMeta: metav1.ObjectMeta{ -// Name: "cstor", -// CreationTimestamp: metav1.Time{time.Now()}, -// Labels: map[string]string{}, -// Finalizers: []string{}, -// }, -// Spec: corev1.NamespaceSpec{Finalizers: []corev1.FinalizerName{corev1.FinalizerKubernetes}}, -//} -//var nsLocalPV = corev1.Namespace{ -// ObjectMeta: metav1.ObjectMeta{ -// Name: "localpv", -// CreationTimestamp: metav1.Time{time.Now()}, +// CreationTimestamp: metav1.Time{Time: time.Now()}, // Labels: map[string]string{}, // Finalizers: []string{}, // }, // Spec: corev1.NamespaceSpec{Finalizers: []corev1.FinalizerName{corev1.FinalizerKubernetes}}, //} + // pvc-1 JivaVolume from jiva namespace attached on worker-node-1 & 1-replica & 2.10.0 //var jv1 = v1alpha1.JivaVolume{ // TypeMeta: metav1.TypeMeta{}, @@ -161,6 +686,7 @@ var jivaPV1 = corev1.PersistentVolume{ Reason: "", }, } + //var jivaPV2 = corev1.PersistentVolume{ // TypeMeta: metav1.TypeMeta{}, // ObjectMeta: metav1.ObjectMeta{ @@ -197,8 +723,8 @@ var pv2 = corev1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: "pvc-1", }, - Spec: corev1.PersistentVolumeSpec{ - Capacity: corev1.ResourceList{corev1.ResourceStorage:resource.Quantity{}}, + Spec: corev1.PersistentVolumeSpec{ + Capacity: corev1.ResourceList{corev1.ResourceStorage: resource.Quantity{}}, }, Status: corev1.PersistentVolumeStatus{}, } @@ -209,4 +735,4 @@ var pv3 = corev1.PersistentVolume{ }, Spec: corev1.PersistentVolumeSpec{}, Status: corev1.PersistentVolumeStatus{}, -} \ No newline at end of file +} diff --git a/pkg/volume/zfs_locapv.go b/pkg/volume/zfs_locapv.go index 21d15a54..3b3fa938 100644 --- a/pkg/volume/zfs_locapv.go +++ b/pkg/volume/zfs_locapv.go @@ -45,7 +45,7 @@ func GetZFSLocalPVs(c *client.K8sClient, pvList *corev1.PersistentVolumeList, op // 3. Show the required ones for _, pv := range pvList.Items { name := pv.Name - capacity := pv.Spec.Capacity.Storage() + capacity := util.ConvertToIBytes(pv.Spec.Capacity.Storage().String()) sc := pv.Spec.StorageClassName attached := pv.Status.Phase var attachedNode, customStatus, ns string diff --git a/pkg/volume/zfs_locapv_test.go b/pkg/volume/zfs_locapv_test.go new file mode 100644 index 00000000..d3ad4f2a --- /dev/null +++ b/pkg/volume/zfs_locapv_test.go @@ -0,0 +1,152 @@ +/* +Copyright 2020-2021 The OpenEBS Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package volume + +import ( + "fmt" + "github.com/openebs/openebsctl/pkg/client" + "github.com/openebs/zfs-localpv/pkg/generated/clientset/internalclientset/fake" + fakezfs "github.com/openebs/zfs-localpv/pkg/generated/clientset/internalclientset/typed/zfs/v1/fake" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + k8sfake "k8s.io/client-go/kubernetes/fake" + k8stest "k8s.io/client-go/testing" + "reflect" + "testing" +) + +func TestGetZFSLocalPVs(t *testing.T) { + type args struct { + c *client.K8sClient + zfsReactors func(*client.K8sClient) + pvList *corev1.PersistentVolumeList + openebsNS string + } + tests := []struct { + name string + args args + want []metav1.TableRow + wantErr bool + }{ + { + name: "no zfs volumes present", + args: args{ + c: &client.K8sClient{ + Ns: "random-namespace", + ZFCS: fake.NewSimpleClientset(), + K8sCS: k8sfake.NewSimpleClientset(), + OpenebsCS: nil, + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{jivaPV1, pv2, pv3}}, + zfsReactors: zfsVolNotExists, + openebsNS: "zfslocalpv", + }, + want: nil, + wantErr: true, + }, + { + name: "only one zfs volume present", + args: args{ + c: &client.K8sClient{ + Ns: "zfslocalpv", + K8sCS: k8sfake.NewSimpleClientset(&localpvzfsCSICtrlSTS), + ZFCS: fake.NewSimpleClientset(&zfsVol1), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{jivaPV1, zfsPV1}}, + openebsNS: "zfslocalpv", + }, + wantErr: false, + want: []metav1.TableRow{ + { + Cells: []interface{}{"zfslocalpv", "pvc-1", "Ready", "1.9.0", "4.0 GiB", "zfs-sc-1", corev1.VolumeBound, corev1.ReadWriteOnce, "node1"}, + }, + }, + }, + { + name: "only one zfs volume present with zfsvol absent", + args: args{ + c: &client.K8sClient{ + Ns: "zfslocalpv", + K8sCS: k8sfake.NewSimpleClientset(&localpvzfsCSICtrlSTS), + ZFCS: fake.NewSimpleClientset(), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{zfsPV1}}, + openebsNS: "zfslocalpv", + }, + wantErr: false, + want: nil, + }, + { + name: "only one zfs volume present, namespace conflicts", + args: args{ + c: &client.K8sClient{ + Ns: "jiva", + K8sCS: k8sfake.NewSimpleClientset(&localpvzfsCSICtrlSTS), + ZFCS: fake.NewSimpleClientset(&zfsVol1), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{jivaPV1, zfsPV1}}, + openebsNS: "zfslocalpvXYZ", + }, + wantErr: false, + want: nil, + }, + { + name: "controller sts not present", + args: args{ + c: &client.K8sClient{ + Ns: "jiva", + K8sCS: k8sfake.NewSimpleClientset(), + ZFCS: fake.NewSimpleClientset(&zfsVol1), + }, + pvList: &corev1.PersistentVolumeList{Items: []corev1.PersistentVolume{jivaPV1, zfsPV1}}, + openebsNS: "zfslocalpv", + }, + wantErr: false, + want: []metav1.TableRow{ + { + Cells: []interface{}{"zfslocalpv", "pvc-1", "Ready", "N/A", "4.0 GiB", "zfs-sc-1", corev1.VolumeBound, corev1.ReadWriteOnce, "node1"}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // 1. Before func + if tt.args.zfsReactors != nil { + tt.args.zfsReactors(tt.args.c) + } + got, err := GetZFSLocalPVs(tt.args.c, tt.args.pvList, tt.args.openebsNS) + if (err != nil) != tt.wantErr { + t.Errorf("GetZFSLocalPVs() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetZFSLocalPVs() got = %v, want %v", got, tt.want) + } + }) + } +} + +// zfsVolNotExists makes fakezfsClientSet return error +func zfsVolNotExists(c *client.K8sClient) { + // NOTE: Set the VERB & Resource correctly & make it work for single resources + c.ZFCS.ZfsV1().(*fakezfs.FakeZfsV1).Fake.PrependReactor("*", "*", func(action k8stest.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, fmt.Errorf("failed to list ZFSVolumes") + }) +} +//