Skip to content

Commit 34477a0

Browse files
committed
Add ListVolumes with PublishedNodes
1 parent 95946b4 commit 34477a0

File tree

13 files changed

+910
-785
lines changed

13 files changed

+910
-785
lines changed

Gopkg.lock

+2-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171

7272
[[constraint]]
7373
name = "github.com/container-storage-interface/spec"
74-
version = "1.1.0"
74+
revision = "9e773d2dd46a9b113d94fb3c245231d231bcfeda"
7575

7676
[[override]]
7777
name = "google.golang.org/grpc"

deploy/kubernetes/overlays/dev/kustomization.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ images:
1010
- name: gke.gcr.io/gcp-compute-persistent-disk-csi-driver
1111
newName: gcr.io/dyzz-csi-staging/csi/gce-pd-driver
1212
newTag: "latest"
13+
- name: gke.gcr.io/csi-attacher
14+
newName: gcr.io/dyzz-csi-staging/csi/csi-attacher
15+
newTag: "latest"

pkg/gce-cloud-provider/compute/fake-gce.go

+4
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ func (cloud *FakeCloudProvider) ListZones(ctx context.Context, region string) ([
9595
return []string{cloud.zone, "country-region-fakesecondzone"}, nil
9696
}
9797

98+
func (cloud *FakeCloudProvider) ListDisks(ctx context.Context, maxEntries int64, pageToken string) ([]*compute.Disk, string, error) {
99+
return nil, "", nil
100+
}
101+
98102
func (cloud *FakeCloudProvider) ListSnapshots(ctx context.Context, filter string, maxEntries int64, pageToken string) ([]*compute.Snapshot, string, error) {
99103
var sourceDisk string
100104
snapshots := []*compute.Snapshot{}

pkg/gce-cloud-provider/compute/gce-compute.go

+19
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type GCECompute interface {
5151
GetDiskTypeURI(volKey *meta.Key, diskType string) string
5252
WaitForAttach(ctx context.Context, volKey *meta.Key, instanceZone, instanceName string) error
5353
ResizeDisk(ctx context.Context, volKey *meta.Key, requestBytes int64) (int64, error)
54+
ListDisks(ctx context.Context, maxEntries int64, pageToken string) ([]*compute.Disk, string, error)
5455
// Regional Disk Methods
5556
GetReplicaZoneURI(zone string) string
5657
// Instance Methods
@@ -63,6 +64,24 @@ type GCECompute interface {
6364
DeleteSnapshot(ctx context.Context, snapshotName string) error
6465
}
6566

67+
// ListDisks lists disks based on maxEntries and pageToken only in the project
68+
// and zone that the driver is running in.
69+
func (cloud *CloudProvider) ListDisks(ctx context.Context, maxEntries int64, pageToken string) ([]*compute.Disk, string, error) {
70+
lCall := cloud.service.Disks.List(cloud.project, cloud.zone)
71+
if maxEntries != 0 {
72+
lCall = lCall.MaxResults(maxEntries)
73+
}
74+
if len(pageToken) != 0 {
75+
lCall = lCall.PageToken(pageToken)
76+
}
77+
diskList, err := lCall.Do()
78+
if err != nil {
79+
return nil, "", fmt.Errorf("failed to list disks from cloud project %s, zone %s, max results %v, page token %s: %v",
80+
cloud.project, cloud.zone, maxEntries, pageToken, err)
81+
}
82+
return diskList.Items, diskList.NextPageToken, nil
83+
}
84+
6685
// RepairUnderspecifiedVolumeKey will query the cloud provider and check each zone for the disk specified
6786
// by the volume key and return a volume key with a correct zone
6887
func (cloud *CloudProvider) RepairUnderspecifiedVolumeKey(ctx context.Context, volumeKey *meta.Key) (*meta.Key, error) {

pkg/gce-pd-csi-driver/controller.go

+28-2
Original file line numberDiff line numberDiff line change
@@ -515,8 +515,34 @@ func (gceCS *GCEControllerServer) ValidateVolumeCapabilities(ctx context.Context
515515

516516
func (gceCS *GCEControllerServer) ListVolumes(ctx context.Context, req *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) {
517517
// https://cloud.google.com/compute/docs/reference/beta/disks/list
518-
// List volumes in the whole region? In only the zone that this controller is running?
519-
return nil, status.Error(codes.Unimplemented, "")
518+
if req.MaxEntries > 500 || req.MaxEntries < 0 {
519+
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf(
520+
"ListVolumes got max entries request %v. GCE only supports values between 0-500", req.MaxEntries))
521+
}
522+
diskList, nextToken, err := gceCS.CloudProvider.ListDisks(ctx, int64(req.MaxEntries), req.StartingToken)
523+
if err != nil {
524+
return nil, status.Error(codes.Internal, fmt.Sprintf("Unknown list disk error: %v", err))
525+
}
526+
entries := []*csi.ListVolumesResponse_Entry{}
527+
for _, d := range diskList {
528+
users := []string{}
529+
for _, u := range d.Users {
530+
users = append(users, cleanSelfLink(u))
531+
}
532+
entries = append(entries, &csi.ListVolumesResponse_Entry{
533+
Volume: &csi.Volume{
534+
VolumeId: cleanSelfLink(d.SelfLink),
535+
},
536+
Status: &csi.ListVolumesResponse_VolumeStatus{
537+
PublishedNodeIds: users,
538+
},
539+
})
540+
}
541+
542+
return &csi.ListVolumesResponse{
543+
Entries: entries,
544+
NextToken: nextToken,
545+
}, nil
520546
}
521547

522548
func (gceCS *GCEControllerServer) GetCapacity(ctx context.Context, req *csi.GetCapacityRequest) (*csi.GetCapacityResponse, error) {

pkg/gce-pd-csi-driver/controller_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,49 @@ func TestCreateVolumeArguments(t *testing.T) {
714714
}
715715
}
716716

717+
func TestListVolumeArgs(t *testing.T) {
718+
testCases := []struct {
719+
name string
720+
maxEntries int32
721+
expErr bool
722+
}{
723+
{
724+
name: "normal",
725+
},
726+
{
727+
name: "fine amount of entries",
728+
maxEntries: 420,
729+
},
730+
{
731+
name: "too many entries",
732+
maxEntries: 501,
733+
expErr: true,
734+
},
735+
{
736+
name: "negative entries",
737+
maxEntries: -1,
738+
expErr: true,
739+
},
740+
}
741+
742+
for _, tc := range testCases {
743+
t.Logf("test case: %s", tc.name)
744+
// Setup new driver each time so no interference
745+
gceDriver := initGCEDriver(t, nil)
746+
lvr := &csi.ListVolumesRequest{
747+
MaxEntries: tc.maxEntries,
748+
}
749+
_, err := gceDriver.cs.ListVolumes(context.TODO(), lvr)
750+
if tc.expErr && err == nil {
751+
t.Fatalf("Got no error when expecting an error")
752+
}
753+
if !tc.expErr && err != nil {
754+
t.Fatalf("Got error %v, expecting none", err)
755+
}
756+
757+
}
758+
}
759+
717760
func TestCreateVolumeWithVolumeSource(t *testing.T) {
718761
// Define test cases
719762
testCases := []struct {

pkg/gce-pd-csi-driver/gce-pd-driver.go

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ func (gceDriver *GCEDriver) SetupGCEDriver(cloudProvider gce.GCECompute, mounter
6767
csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
6868
csi.ControllerServiceCapability_RPC_PUBLISH_READONLY,
6969
csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
70+
csi.ControllerServiceCapability_RPC_LIST_VOLUMES_PUBLISHED_NODES,
7071
}
7172
gceDriver.AddControllerServiceCapabilities(csc)
7273
ns := []csi.NodeServiceCapability_RPC_Type{

test/e2e/tests/single_zone_e2e_test.go

+60
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"k8s.io/apimachinery/pkg/util/wait"
2525
"sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/common"
2626
gce "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/gce-cloud-provider/compute"
27+
"sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/test/remote"
2728

2829
csi "github.com/container-storage-interface/spec/lib/go/csi"
2930
. "github.com/onsi/ginkgo"
@@ -466,6 +467,36 @@ var _ = Describe("GCE PD CSI Driver", func() {
466467
Expect(err).To(BeNil(), "Failed to go through volume lifecycle after restoring CMEK key")
467468
})
468469

470+
It("Should create disks, attach them places, and verify List returns correct results", func() {
471+
Expect(testContexts).ToNot(BeEmpty())
472+
testContext := getRandomTestContext()
473+
474+
p, z, _ := testContext.Instance.GetIdentity()
475+
client := testContext.Client
476+
477+
nodeID := testContext.Instance.GetNodeID()
478+
479+
volID := createUniqueVolumeOrError(client, p, z)
480+
defer deleteVolumeOrError(client, volID, p)
481+
482+
secondVolID := createUniqueVolumeOrError(client, p, z)
483+
defer deleteVolumeOrError(client, secondVolID, p)
484+
485+
// Attach volID to current instance
486+
err := client.ControllerPublishVolume(volID, nodeID)
487+
Expect(err).To(BeNil(), "Failed ControllerPublishVolume")
488+
defer client.ControllerUnpublishVolume(volID, nodeID)
489+
490+
// List Volumes
491+
volsToNodes, err := client.ListVolumes()
492+
Expect(err).To(BeNil(), "Failed ListVolumes")
493+
494+
// Verify
495+
Expect(volsToNodes[volID]).ToNot(BeNil(), "Couldn't find attached nodes for vol")
496+
Expect(volsToNodes[volID]).To(ContainElement(nodeID), "Couldn't find node in attached nodes for vol")
497+
Expect(volsToNodes[secondVolID]).To(BeNil(), "Second vol ID attached nodes not nil")
498+
})
499+
469500
It("Should create and delete snapshot for RePD in two zones ", func() {
470501
Expect(testContexts).ToNot(BeEmpty())
471502
testContext := getRandomTestContext()
@@ -540,3 +571,32 @@ var _ = Describe("GCE PD CSI Driver", func() {
540571
}()
541572
})
542573
})
574+
575+
func createUniqueVolumeOrError(client *remote.CsiClient, project, zone string) string {
576+
// Create Disk
577+
volName := testNamePrefix + string(uuid.NewUUID())
578+
volID, err := client.CreateVolume(volName, nil, defaultSizeGb, nil)
579+
Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err)
580+
581+
// Validate Disk Created
582+
cloudDisk, err := computeService.Disks.Get(project, zone, volName).Do()
583+
Expect(err).To(BeNil(), "Could not get disk from cloud directly")
584+
Expect(cloudDisk.Type).To(ContainSubstring(standardDiskType))
585+
Expect(cloudDisk.Status).To(Equal(readyState))
586+
Expect(cloudDisk.SizeGb).To(Equal(defaultSizeGb))
587+
Expect(cloudDisk.Name).To(Equal(volName))
588+
589+
return volID
590+
}
591+
592+
func deleteVolumeOrError(client *remote.CsiClient, volID, project string) {
593+
// Delete Disk
594+
err := client.DeleteVolume(volID)
595+
Expect(err).To(BeNil(), "DeleteVolume failed")
596+
597+
// Validate Disk Deleted
598+
key, err := common.VolumeIDToKey(volID)
599+
Expect(err).To(BeNil(), "Failed to conver volume ID To key")
600+
_, err = computeService.Disks.Get(project, key.Zone, key.Name).Do()
601+
Expect(gce.IsGCEError(err, "notFound")).To(BeTrue(), "Expected disk to not be found")
602+
}

test/remote/client-wrappers.go

+12
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,18 @@ func (c *CsiClient) ControllerPublishVolume(volId, nodeId string) error {
138138
return err
139139
}
140140

141+
func (c *CsiClient) ListVolumes() (map[string]([]string), error) {
142+
resp, err := c.ctrlClient.ListVolumes(context.Background(), &csipb.ListVolumesRequest{})
143+
if err != nil {
144+
return nil, err
145+
}
146+
vols := map[string]([]string){}
147+
for _, e := range resp.Entries {
148+
vols[e.Volume.VolumeId] = e.Status.PublishedNodeIds
149+
}
150+
return vols, nil
151+
}
152+
141153
func (c *CsiClient) ControllerUnpublishVolume(volId, nodeId string) error {
142154
cupreq := &csipb.ControllerUnpublishVolumeRequest{
143155
VolumeId: volId,

test/remote/instance.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package remote
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223
"io/ioutil"
2324
"net/http"
@@ -137,9 +138,9 @@ func (i *InstanceInfo) CreateOrGetInstance(serviceAccount string) error {
137138
if err != nil {
138139
ret := fmt.Sprintf("could not create instance %s: API error: %v", i.name, err)
139140
if op != nil {
140-
ret = fmt.Sprintf("%s: %v", ret, op.Error)
141+
ret = fmt.Sprintf("%s. op error: %v", ret, op.Error)
141142
}
142-
return fmt.Errorf(ret)
143+
return errors.New(ret)
143144
} else if op.Error != nil {
144145
return fmt.Errorf("could not create instance %s: %+v", i.name, op.Error)
145146
}

0 commit comments

Comments
 (0)