Skip to content

Commit edc1a4f

Browse files
authored
Merge pull request #154 from darkowlzz/create-vol-from-source
Add tests for volume creation from source
2 parents 4525788 + de9122e commit edc1a4f

File tree

3 files changed

+185
-2
lines changed

3 files changed

+185
-2
lines changed

mock/service/controller.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,33 @@ func (s *service) CreateVolume(
5757
if capacity >= MaxStorageCapacity {
5858
return nil, status.Errorf(codes.OutOfRange, "Requested capacity %d exceeds maximum allowed %d", capacity, MaxStorageCapacity)
5959
}
60-
// Create the volume and add it to the service's in-mem volume slice.
61-
v := s.newVolume(req.Name, capacity)
60+
61+
var v csi.Volume
62+
// Create volume from content source if provided.
63+
if req.GetVolumeContentSource() != nil {
64+
switch req.GetVolumeContentSource().GetType().(type) {
65+
case *csi.VolumeContentSource_Snapshot:
66+
sid := req.GetVolumeContentSource().GetSnapshot().GetSnapshotId()
67+
// Check if the source snapshot exists.
68+
if snapID, _ := s.snapshots.FindSnapshot("id", sid); snapID >= 0 {
69+
v = s.newVolumeFromSnapshot(req.Name, capacity, snapID)
70+
} else {
71+
return nil, status.Errorf(codes.NotFound, "Requested source snapshot %s not found", sid)
72+
}
73+
case *csi.VolumeContentSource_Volume:
74+
vid := req.GetVolumeContentSource().GetVolume().GetVolumeId()
75+
// Check if the source volume exists.
76+
if volID, _ := s.findVolNoLock("id", vid); volID > 0 {
77+
v = s.newVolumeFromVolume(req.Name, capacity, volID)
78+
} else {
79+
return nil, status.Errorf(codes.NotFound, "Requested source volume %s not found", vid)
80+
}
81+
}
82+
} else {
83+
v = s.newVolume(req.Name, capacity)
84+
}
85+
86+
// Add the created volume to the service's in-mem volume slice.
6287
s.volsRWL.Lock()
6388
defer s.volsRWL.Unlock()
6489
s.vols = append(s.vols, v)
@@ -398,6 +423,13 @@ func (s *service) ControllerGetCapabilities(
398423
},
399424
},
400425
},
426+
{
427+
Type: &csi.ControllerServiceCapability_Rpc{
428+
Rpc: &csi.ControllerServiceCapability_RPC{
429+
Type: csi.ControllerServiceCapability_RPC_CLONE_VOLUME,
430+
},
431+
},
432+
},
401433
}
402434

403435
if !s.config.DisableAttach {

mock/service/service.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,30 @@ func (s *service) newVolume(name string, capcity int64) csi.Volume {
103103
}
104104
}
105105

106+
func (s *service) newVolumeFromSnapshot(name string, capacity int64, snapshotID int) csi.Volume {
107+
vol := s.newVolume(name, capacity)
108+
vol.ContentSource = &csi.VolumeContentSource{
109+
Type: &csi.VolumeContentSource_Snapshot{
110+
Snapshot: &csi.VolumeContentSource_SnapshotSource{
111+
SnapshotId: string(snapshotID),
112+
},
113+
},
114+
}
115+
return vol
116+
}
117+
118+
func (s *service) newVolumeFromVolume(name string, capacity int64, volumeID int) csi.Volume {
119+
vol := s.newVolume(name, capacity)
120+
vol.ContentSource = &csi.VolumeContentSource{
121+
Type: &csi.VolumeContentSource_Volume{
122+
Volume: &csi.VolumeContentSource_VolumeSource{
123+
VolumeId: string(volumeID),
124+
},
125+
},
126+
}
127+
return vol
128+
}
129+
106130
func (s *service) findVol(k, v string) (volIdx int, volInfo csi.Volume) {
107131
s.volsRWL.RLock()
108132
defer s.volsRWL.RUnlock()

pkg/sanity/controller.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,133 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
508508
Expect(err).NotTo(HaveOccurred())
509509
cl.UnregisterVolume(name)
510510
})
511+
512+
It("should create volume from an existing source snapshot", func() {
513+
if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
514+
Skip("Snapshot not supported")
515+
}
516+
517+
By("creating a volume")
518+
vol1Name := uniqueString("sanity-controller-source-vol")
519+
vol1Req := MakeCreateVolumeReq(sc, vol1Name)
520+
volume1, err := c.CreateVolume(context.Background(), vol1Req)
521+
Expect(err).NotTo(HaveOccurred())
522+
523+
By("creating a snapshot")
524+
snapName := uniqueString("sanity-controller-snap-from-vol")
525+
snapReq := MakeCreateSnapshotReq(sc, snapName, volume1.GetVolume().GetVolumeId(), nil)
526+
snap, err := c.CreateSnapshot(context.Background(), snapReq)
527+
Expect(err).NotTo(HaveOccurred())
528+
Expect(snap).NotTo(BeNil())
529+
verifySnapshotInfo(snap.GetSnapshot())
530+
531+
By("creating a volume from source snapshot")
532+
vol2Name := uniqueString("sanity-controller-vol-from-snap")
533+
vol2Req := MakeCreateVolumeReq(sc, vol2Name)
534+
vol2Req.VolumeContentSource = &csi.VolumeContentSource{
535+
Type: &csi.VolumeContentSource_Snapshot{
536+
Snapshot: &csi.VolumeContentSource_SnapshotSource{
537+
SnapshotId: snap.GetSnapshot().GetSnapshotId(),
538+
},
539+
},
540+
}
541+
volume2, err := c.CreateVolume(context.Background(), vol2Req)
542+
Expect(err).NotTo(HaveOccurred())
543+
544+
By("cleaning up deleting the volume created from snapshot")
545+
delVol2Req := MakeDeleteVolumeReq(sc, volume2.GetVolume().GetVolumeId())
546+
_, err = c.DeleteVolume(context.Background(), delVol2Req)
547+
Expect(err).NotTo(HaveOccurred())
548+
549+
By("cleaning up deleting the snapshot")
550+
delSnapReq := MakeDeleteSnapshotReq(sc, snap.GetSnapshot().GetSnapshotId())
551+
_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
552+
Expect(err).NotTo(HaveOccurred())
553+
554+
By("cleaning up deleting the source volume")
555+
delVol1Req := MakeDeleteVolumeReq(sc, volume1.GetVolume().GetVolumeId())
556+
_, err = c.DeleteVolume(context.Background(), delVol1Req)
557+
Expect(err).NotTo(HaveOccurred())
558+
})
559+
560+
It("should fail when the volume source snapshot is not found", func() {
561+
if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
562+
Skip("Snapshot not supported")
563+
}
564+
565+
By("creating a volume from source snapshot")
566+
volName := uniqueString("sanity-controller-vol-from-snap")
567+
volReq := MakeCreateVolumeReq(sc, volName)
568+
volReq.VolumeContentSource = &csi.VolumeContentSource{
569+
Type: &csi.VolumeContentSource_Snapshot{
570+
Snapshot: &csi.VolumeContentSource_SnapshotSource{
571+
SnapshotId: "non-existing-snapshot-id",
572+
},
573+
},
574+
}
575+
_, err := c.CreateVolume(context.Background(), volReq)
576+
Expect(err).To(HaveOccurred())
577+
serverError, ok := status.FromError(err)
578+
Expect(ok).To(BeTrue())
579+
Expect(serverError.Code()).To(Equal(codes.NotFound))
580+
})
581+
582+
It("should create volume from an existing source volume", func() {
583+
if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CLONE_VOLUME) {
584+
Skip("Volume Cloning not supported")
585+
}
586+
587+
By("creating a volume")
588+
vol1Name := uniqueString("sanity-controller-source-vol")
589+
vol1Req := MakeCreateVolumeReq(sc, vol1Name)
590+
volume1, err := c.CreateVolume(context.Background(), vol1Req)
591+
Expect(err).NotTo(HaveOccurred())
592+
593+
By("creating a volume from source volume")
594+
vol2Name := uniqueString("sanity-controller-vol-from-vol")
595+
vol2Req := MakeCreateVolumeReq(sc, vol2Name)
596+
vol2Req.VolumeContentSource = &csi.VolumeContentSource{
597+
Type: &csi.VolumeContentSource_Volume{
598+
Volume: &csi.VolumeContentSource_VolumeSource{
599+
VolumeId: volume1.GetVolume().GetVolumeId(),
600+
},
601+
},
602+
}
603+
volume2, err := c.CreateVolume(context.Background(), vol2Req)
604+
Expect(err).NotTo(HaveOccurred())
605+
606+
By("cleaning up deleting the volume created from source volume")
607+
delVol2Req := MakeDeleteVolumeReq(sc, volume2.GetVolume().GetVolumeId())
608+
_, err = c.DeleteVolume(context.Background(), delVol2Req)
609+
Expect(err).NotTo(HaveOccurred())
610+
611+
By("cleaning up deleting the source volume")
612+
delVol1Req := MakeDeleteVolumeReq(sc, volume1.GetVolume().GetVolumeId())
613+
_, err = c.DeleteVolume(context.Background(), delVol1Req)
614+
Expect(err).NotTo(HaveOccurred())
615+
})
616+
617+
It("should fail when the volume source volume is not found", func() {
618+
if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CLONE_VOLUME) {
619+
Skip("Volume Cloning not supported")
620+
}
621+
622+
By("creating a volume from source snapshot")
623+
volName := uniqueString("sanity-controller-vol-from-snap")
624+
volReq := MakeCreateVolumeReq(sc, volName)
625+
volReq.VolumeContentSource = &csi.VolumeContentSource{
626+
Type: &csi.VolumeContentSource_Volume{
627+
Volume: &csi.VolumeContentSource_VolumeSource{
628+
VolumeId: "non-existing-volume-id",
629+
},
630+
},
631+
}
632+
_, err := c.CreateVolume(context.Background(), volReq)
633+
Expect(err).To(HaveOccurred())
634+
serverError, ok := status.FromError(err)
635+
Expect(ok).To(BeTrue())
636+
Expect(serverError.Code()).To(Equal(codes.NotFound))
637+
})
511638
})
512639

513640
Describe("DeleteVolume", func() {

0 commit comments

Comments
 (0)