-
Notifications
You must be signed in to change notification settings - Fork 332
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
Restore Volume from Snapshot #123
Conversation
This PR adds changes to support restoring a volume from a snapshot. Note: The DataSource addition in core API (kubernetes/kubernetes#67087) and snapshot API/controller changes (kubernetes-csi/external-snapshotter#7) are merged.
pkg/controller/controller.go
Outdated
var checkSnapshotSupport bool | ||
if options.PVC.Spec.DataSource != nil { | ||
// PVC.Spec.DataSource.Name is the name of the VolumeSnapshot API object | ||
if options.PVC.Spec.DataSource.Name == "" { |
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.
Since validation code already check this, do we need these checks here?
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.
Actually these can be removed now. I'll remove them.
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.
Maybe we should keep these checks here? When we add support for more Data Source types, the validation check will be changed to allow other Data Sources.
pkg/controller/controller.go
Outdated
if checkSnapshotSupport { | ||
snapshotObj, err := p.snapshotClient.VolumesnapshotV1alpha1().VolumeSnapshots(options.PVC.Namespace).Get(options.PVC.Spec.DataSource.Name, metav1.GetOptions{}) | ||
if err != nil { | ||
return nil, fmt.Errorf("error get snapshot %s from api server: %v", options.PVC.Spec.DataSource.Name, 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.
error getting ..?
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.
Sure.
pkg/controller/controller.go
Outdated
} | ||
glog.V(5).Infof("VolumeSnapshot %+v", snapshotObj) | ||
|
||
snapContentObj, err := p.snapshotClient.VolumesnapshotV1alpha1().VolumeSnapshotContents().Get(snapshotObj.Spec.SnapshotContentName, metav1.GetOptions{}) |
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.
Maybe we can check VolumeSnapshot status to see whether it is ready?
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.
Good point
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.
Done
pkg/controller/controller.go
Outdated
@@ -69,13 +71,17 @@ const ( | |||
backoffSteps = 10 | |||
|
|||
defaultFSType = "ext4" | |||
|
|||
snapshotKind = "VolumeSnapshot" | |||
snapshotAPIGroup = "snapshot.storage.k8s.io" |
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.
Quick question, shouldn't these values come from external-snapshotter library?
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.
Looks like I can get GroupName from snapshot api package. It is a constant there.
As for "VolumeSnapshot", it is a struct defined in types.go but there is no constant. I think I can get it by instantiating it first and then use "reflect" to get it, but it seems weird to get it that way. I haven't found an easier way.
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.
Changed snapshotAPIGroup to use GroupName from external-snapshotter lib.
pkg/controller/controller.go
Outdated
@@ -257,6 +292,21 @@ func checkDriverState(grpcClient *grpc.ClientConn, timeout time.Duration) (strin | |||
glog.Error("no create/delete volume support detected") | |||
return "", fmt.Errorf("no create/delete volume support detected") | |||
} | |||
|
|||
if checkSnapshotSupport { |
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.
Comment here in what situation the code should not check for support.
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.
Done
pkg/controller/controller.go
Outdated
@@ -289,7 +339,21 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis | |||
return nil, fmt.Errorf("claim Selector is not supported") | |||
} | |||
|
|||
driverName, err := checkDriverState(p.grpcClient, p.timeout) | |||
var checkSnapshotSupport bool |
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.
call it needSnapshotSupport?
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.
Done
pkg/controller/controller.go
Outdated
@@ -317,6 +381,46 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis | |||
RequiredBytes: int64(volSizeBytes), | |||
}, | |||
} | |||
|
|||
if checkSnapshotSupport { |
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.
maybe to put this part into a separate function to get snapshot handler?
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.
Done
pkg/controller/controller.go
Outdated
} | ||
checkSnapshotSupport = true | ||
} | ||
driverName, err := checkDriverState(p.grpcClient, p.timeout, checkSnapshotSupport) |
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.
Consider we will keep adding more types of data sources, a boolean value added here might not be convenient. But we could change it later.
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.
Sure
pkg/controller/controller.go
Outdated
@@ -537,6 +512,51 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis | |||
return pv, nil | |||
} | |||
|
|||
func (p *csiProvisioner) getSnapshotHandle(options controller.VolumeOptions) (*csi.VolumeContentSource, error) { |
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.
maybe call it getVolumeContentSource?
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.
Sure
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.
Done
f28996a
to
a496622
Compare
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.
mostly looks good to me, just a couple nits and questions! Thanks for working on this :)
Gopkg.toml
Outdated
@@ -40,14 +44,19 @@ | |||
name = "google.golang.org/grpc" | |||
version = "1.9.2" | |||
|
|||
[[constraint]] | |||
[[override]] |
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.
these probably do not have to be overrides, constraint should be better for most of these as they will behave correct if dependencies are removed/changed. We only need to override if we transitively depend on a certain version of a package, but I believe most of these are direct dependencies so we should just use [[constraint]]
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 added "override" because I ran into errors earlier without them. I just removed them and re-ran them. It works now.
@@ -86,6 +87,10 @@ func init() { | |||
if err != nil { | |||
glog.Fatalf("Failed to create client: %v", err) | |||
} | |||
snapClient, err := snapclientset.NewForConfig(config) |
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.
What does NewForConfig
mean? is it NewSnapClientFromConfig
?
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.
Added a comment for this: "NewForConfig creates a new Clientset for VolumesnapshotV1alpha1Client"
pkg/controller/controller.go
Outdated
@@ -289,7 +343,21 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis | |||
return nil, fmt.Errorf("claim Selector is not supported") | |||
} | |||
|
|||
driverName, err := checkDriverState(p.grpcClient, p.timeout) | |||
var needSnapshotSupport bool |
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.
nit: explicitly set needSnapshotSupport := false
here
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.
Done
pkg/controller/controller.go
Outdated
req.VolumeContentSource = volumeContentSource | ||
} | ||
|
||
glog.Infof("CreateVolumeRequest %+v", req) |
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.
remove debug logs or decrease verbosity
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.
Changed to glog.V(5).Infof
pkg/controller/controller.go
Outdated
|
||
snapshotSource := csi.VolumeContentSource_Snapshot{ | ||
Snapshot: &csi.VolumeContentSource_SnapshotSource{ | ||
Id: snapContentObj.Spec.VolumeSnapshotSource.CSI.SnapshotHandle, |
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.
nit: nil check on this SnapshotHandle
?
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.
Done
pkg/controller/controller.go
Outdated
glog.V(5).Infof("VolumeContentSource_Snapshot %+v", snapshotSource) | ||
|
||
if snapshotObj.Status.RestoreSize != nil { | ||
capacity := options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] |
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.
nit: exists check
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.
Done
pkg/controller/controller_test.go
Outdated
volOpts controller.VolumeOptions | ||
restoredVolSizeSmall bool | ||
wrongDataSource bool | ||
validSnapshotStatus bool |
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.
nit: rename to snapshotStatusReady
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.
Done
pkg/controller/controller_test.go
Outdated
@@ -511,6 +620,42 @@ func provisionMockServerSetupExpectations(identityServer *driver.MockIdentitySer | |||
}, nil).Times(1) | |||
} | |||
|
|||
func provisionFromSnapshotMockServerSetupExpectations(identityServer *driver.MockIdentityServer, controllerServer *driver.MockControllerServer) { |
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.
Its not incredibly clear what expectations we have here, could you add a comment explaining what expectations these are and what we use them for?
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.
Added comments
pkg/controller/controller_test.go
Outdated
} | ||
|
||
// Setup mock call expectations. | ||
if tc.wrongDataSource == false { |
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.
its not clear to me what this means and why we do this
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.
Added the following comments:
// If tc.wrongDataSource is false, DataSource is valid
// and the controller will proceed to check whether the plugin supports snapshot.
// So in this case, we need the plugin to report snapshot support capabilities;
// Otherwise, the controller will fail the operation so it won't check the capabilities.
pkg/controller/controller_test.go
Outdated
if tc.wrongDataSource == false { | ||
provisionFromSnapshotMockServerSetupExpectations(identityServer, controllerServer) | ||
} | ||
if tc.restoredVolSizeSmall == false && tc.wrongDataSource == false && tc.validSnapshotStatus { |
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.
what happens if any of these are true? Specifically if restoredVolSizeSmall
is true it doesn't look like we do anything special
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.
Added the following comments:
// If tc.restoredVolSizeSmall is true, or tc.wrongDataSource is true, or
// tc.snapshotStatusReady is false, create volume from snapshot operation will fail
// early and therefore CreateVolume is not expected to be called.
// When the if condition is met, it is a valid create volume from snapshot
// operation and CreateVolume is expected to be called.
pkg/controller/controller.go
Outdated
@@ -529,6 +529,10 @@ func (p *csiProvisioner) getVolumeContentSource(options controller.VolumeOptions | |||
} | |||
glog.V(5).Infof("VolumeSnapshotContent %+v", snapContentObj) | |||
|
|||
if snapContentObj.Spec.VolumeSnapshotSource.CSI == nil || len(snapContentObj.Spec.VolumeSnapshotSource.CSI.SnapshotHandle) == 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.
Just to confirm we don't need to check Spec.VolumeSnapshotSource because it is required field?
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.
Yes, Spec.VolumeSnapshotSource is required but Spec.VolumeSnapshotSource.CSI could be nil. If CSI is specified, SnapshotHandle is required so that check can be removed.
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.
So I removed the check for SnapshotHandle but kept the check for CSI is nil. Let me know if this is okay.
9a36e5e
to
c736242
Compare
@jingxu97 @davidz627 @lpabon Review comments are addressed. Can you please review again? Thanks! |
/lgtm |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: lpabon, xing-yang 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 |
Use Connection() from util package
This PR adds changes to support restoring a volume from a snapshot.
The DataSource addition in core API (kubernetes/kubernetes#67087) and snapshot API/controller changes (kubernetes-csi/external-snapshotter#7) are merged now.