-
Notifications
You must be signed in to change notification settings - Fork 634
[cinder-csi-plugin] Refactor list volumes #2766
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[cinder-csi-plugin] Refactor list volumes #2766
Conversation
Welcome @kon-angelo! |
Hi @kon-angelo. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
/ok-to-test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR. It took me a while to understand this logic, since I didn't review the initial #2551 and I don't have environment with a multi-region setup. See my comments below.
pkg/csi/cinder/controllerserver.go
Outdated
@@ -33,11 +33,12 @@ import ( | |||
"google.golang.org/grpc/status" | |||
"google.golang.org/protobuf/types/known/timestamppb" | |||
|
|||
"k8s.io/klog/v2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you please move this back?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kindly ping
@@ -437,7 +438,7 @@ func genFakeVolumeEntry(fakeVol volumes.Volume) *csi.ListVolumesResponse_Entry { | |||
} | |||
} | |||
func genFakeVolumeEntries(fakeVolumes []volumes.Volume) []*csi.ListVolumesResponse_Entry { | |||
var entries []*csi.ListVolumesResponse_Entry | |||
entries := make([]*csi.ListVolumesResponse_Entry, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
entries := make([]*csi.ListVolumesResponse_Entry, 0) | |
entries := make([]*csi.ListVolumesResponse_Entry, len(fakeVolumes)) |
pkg/csi/cinder/controllerserver.go
Outdated
@@ -444,7 +444,6 @@ func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolume | |||
var cloudsToken = CloudsStartingToken{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's enough to have var cloudsToken CloudsStartingToken
pkg/csi/cinder/controllerserver.go
Outdated
@@ -405,7 +406,6 @@ func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req * | |||
type CloudsStartingToken struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's better to move the type declaration to the top and make it private, since it's not used anywhere else
pkg/csi/cinder/controllerserver.go
Outdated
Entries: cloudsVentries, | ||
NextToken: string(data), | ||
}, nil | ||
volumeList, nextPageToken, err := cs.Clouds[cloudsNames[idx]].ListVolumes(ctx, maxEntries, startingToken) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
volumeList, nextPageToken, err := cs.Clouds[cloudsNames[idx]].ListVolumes(ctx, maxEntries, startingToken) | |
volumeList, cloudsToken.Token, err := cs.Clouds[cloudsNames[idx]].ListVolumes(ctx, maxEntries, startingToken) |
pkg/csi/cinder/controllerserver.go
Outdated
volumeEntries := cs.createVolumeEntries(volumeList) | ||
klog.V(4).Infof("ListVolumes: retrieved %d entries and %q next token from cloud %q", len(volumeEntries), nextPageToken, cloudsNames[idx]) | ||
|
||
cloudsToken.Token = nextPageToken |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cloudsToken.Token = nextPageToken |
pkg/csi/cinder/controllerserver.go
Outdated
} | ||
|
||
startIdx := 0 | ||
idx := 0 | ||
for _, cloudName := range cloudsNames { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why do we need to loop over cloud names? If you take a look at the ListSnapshots
method, the cloud name is taken directly from the volCloud := req.GetSecrets()["cloud"]
. Why not to do the same here? @MatthieuFin could you please clarify this logic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @kayrus I'm currently on vacation but I can give you some hint from my memories, usage of "secrets" with volCloud := req.GetSecrets()["cloud"]
method is more a hack than a feature as explain on my PR, I got inspired by discussion in this issue where usage of secrets fields in gRPC csi spec to store current cloud.
So now that clear, we can simply use "secrets" field in gRPC call for ListSnapshots
because csi spec provide a 'secrets" field in gRPC csi spec here that is fully convenient. This secret is filled by informations provided in StorageClass (I guess we list Snapshot of a SC or snapshot of a defined volume but never globally all snapshots)
But unfortunatelly (I don't remember why, but I guess that there is an explanation) in ListVolume
call we implement gRPC call spec ListVolumesRequest where there is no secrets
field but only max_entries
and starting_token
so as we don't have possibility to know which cloud is concerned (and that make sens we wanna list "k8s" volumes which concern all our clouds) we have to loop over each clouds, and I use "token" in JSON format (if I remember right) to store processed cloud and keep a "state" if ListVolume use pagination, in that way if a client provide a max_entries != 0
the token permit us to know which cloud we have to call to retrieve next volumes.
To be honest that not my proudest implementation (ListVolume function), I have maybe made some error, but I didn"t notice it for now, I'll take a look on this issue on my side when i'll back to work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MatthieuFin I think this is correct. There is no way to get the cloud
info as there is no secrets field in the request - you simply need to list everything from your current configuration.
@kayrus The reason to loop over the cloud
names is because we are creating a stable index of all the available clouds
. Henceforth, we can know from the token which is the next cloud we need to list volumes for. I also don't see (at the moment at least) another way to know this info.
I quickly read @kon-angelo's |
mc := metrics.NewMetricContext("volume", "list") | ||
opts := volumes.ListOpts{Limit: limit, Marker: startingToken} | ||
if limit == 0 { | ||
page, err := volumes.List(os.blockstorage, opts).AllPages(context.Background()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use the ctx
page, err := volumes.List(os.blockstorage, opts).AllPages(context.Background()) | |
page, err := volumes.List(os.blockstorage, opts).AllPages(ctx) |
pkg/csi/cinder/controllerserver.go
Outdated
) | ||
|
||
type controllerServer struct { | ||
Driver *Driver | ||
Clouds map[string]openstack.IOpenStack | ||
} | ||
|
||
type cloudsStartingToken struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also wonder whether it's better to use <token>:<cloud>
format and use SplitN
along with Join
to avoid useless json encoding/decoding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will provide a commit that changes the token to the colon-separated one. We don't care about any kind of backwards-compatibility here so it should be straightforward to change
pkg/csi/cinder/controllerserver.go
Outdated
@@ -33,11 +33,12 @@ import ( | |||
"google.golang.org/grpc/status" | |||
"google.golang.org/protobuf/types/known/timestamppb" | |||
|
|||
"k8s.io/klog/v2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kindly ping
797a55b
to
47aa102
Compare
47aa102
to
f99d400
Compare
mc := metrics.NewMetricContext("volume", "list") | ||
opts := volumes.ListOpts{Limit: limit, Marker: startingToken} | ||
if limit == 0 { | ||
page, err := volumes.List(os.blockstorage, opts).AllPages(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in this case there is no need to provide opts
page, err := volumes.List(os.blockstorage, opts).AllPages(ctx) | |
page, err := volumes.List(os.blockstorage, nil).AllPages(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be addressed now
pkg/csi/cinder/controllerserver.go
Outdated
@@ -32,7 +32,6 @@ import ( | |||
"google.golang.org/grpc/codes" | |||
"google.golang.org/grpc/status" | |||
"google.golang.org/protobuf/types/known/timestamppb" | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please leave it as is. this will help to avoid issues in backporting.
vols, err = volumes.ExtractVolumes(page) | ||
if mc.ObserveRequest(err) != nil { | ||
return vols, "", err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
} | |
return vols, "", nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @kon-angelo! Almost perfect. I just left some nit comments, and I hope we're ready to go.
cloud string | ||
}{ | ||
{input: "foo:bar", token: "foo", cloud: "bar"}, | ||
{input: "foo", token: "foo", cloud: ""}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just in case
{input: "foo", token: "foo", cloud: ""}, | |
{input: "foo", token: "foo", cloud: ""}, | |
{input: "foo:", token: "foo", cloud: ""}, |
{input: "foo:bar", token: "foo", cloud: "bar"}, | ||
{input: "foo", token: "foo", cloud: ""}, | ||
{input: ":bar", token: "", cloud: "bar"}, | ||
{input: "foo:bar:baz", token: "foo", cloud: "bar:baz"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{input: "foo:bar:baz", token: "foo", cloud: "bar:baz"}, | |
{input: "foo:bar:baz", token: "foo", cloud: "bar:baz"}, | |
{input: "", token: "", cloud: ""}, |
pkg/csi/cinder/controllerserver.go
Outdated
NextToken: string(data), | ||
}, nil | ||
var volumeList []volumes.Volume | ||
volumeList, token, err = cs.Clouds[cloudsNames[idx]].ListVolumes(ctx, maxEntries, token) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can simply use cloudName
here
volumeList, token, err = cs.Clouds[cloudsNames[idx]].ListVolumes(ctx, maxEntries, token) | |
volumeList, token, err = cs.Clouds[cloudName].ListVolumes(ctx, maxEntries, token) |
pkg/csi/cinder/controllerserver.go
Outdated
return nil, status.Errorf(codes.Internal, "ListVolumes failed with error %v", err) | ||
} | ||
volumeEntries := cs.createVolumeEntries(volumeList) | ||
klog.V(4).Infof("ListVolumes: retrieved %d entries and %q next token from cloud %q", len(volumeEntries), token, cloudsNames[idx]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and here too
klog.V(4).Infof("ListVolumes: retrieved %d entries and %q next token from cloud %q", len(volumeEntries), token, cloudsNames[idx]) | |
klog.V(4).Infof("ListVolumes: retrieved %d entries and %q next token from cloud %q", len(volumeEntries), token, cloudName) |
/lgtm |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: kayrus The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/cherry-pick release-1.31 |
@kayrus: once the present PR merges, I will cherry-pick it on top of In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
/test openstack-cloud-csi-cinder-e2e-test |
@kayrus: #2766 failed to apply on top of branch "release-1.31":
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
* refactor list volumes call * upgrade tests * comments improvements * fix imports and list options * token split * add more jointoken tests
* refactor list volumes call * upgrade tests * comments improvements * fix imports and list options * token split * add more jointoken tests Co-authored-by: Konstantinos Angelopoulos <[email protected]>
What this PR does / why we need it:
Fixes the linked issue and in addition does a small refactoring simplifying the code for the list volumes. In particular it changes the behavior slightly in 2 ways:
Regarding point 2: the external-attacher will continue sending requests to list volumes while the response contains a token:
https://github.com/kubernetes-csi/external-attacher/blob/e5ae92e87bb6c3d99061ca515285c5c9e76e0414/pkg/attacher/lister.go#L63-L65
With this change, we will expect the csi-attacher to issue a request per cloud in our configuration.
Which issue this PR fixes(if applicable):
fixes #2764
Special notes for reviewers:
Release note: