Skip to content
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

Merged
merged 6 commits into from
Sep 5, 2018

Conversation

xing-yang
Copy link
Contributor

@xing-yang xing-yang commented Aug 10, 2018

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.

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Aug 19, 2018
@k8s-ci-robot k8s-ci-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 30, 2018
@xing-yang xing-yang changed the title WIP: Restore Volume from Snapshot Restore Volume from Snapshot Aug 30, 2018
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 30, 2018
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.
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 == "" {
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error getting ..?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

}
glog.V(5).Infof("VolumeSnapshot %+v", snapshotObj)

snapContentObj, err := p.snapshotClient.VolumesnapshotV1alpha1().VolumeSnapshotContents().Get(snapshotObj.Spec.SnapshotContentName, metav1.GetOptions{})
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -69,13 +71,17 @@ const (
backoffSteps = 10

defaultFSType = "ext4"

snapshotKind = "VolumeSnapshot"
snapshotAPIGroup = "snapshot.storage.k8s.io"
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

@@ -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 {
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call it needSnapshotSupport?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -317,6 +381,46 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
RequiredBytes: int64(volSizeBytes),
},
}

if checkSnapshotSupport {
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
checkSnapshotSupport = true
}
driverName, err := checkDriverState(p.grpcClient, p.timeout, checkSnapshotSupport)
Copy link
Contributor

@jingxu97 jingxu97 Aug 31, 2018

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

@@ -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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe call it getVolumeContentSource?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

@davidz627 davidz627 left a 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]]
Copy link
Contributor

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]]

Copy link
Contributor Author

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)
Copy link
Contributor

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?

Copy link
Contributor Author

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"

@@ -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
Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

req.VolumeContentSource = volumeContentSource
}

glog.Infof("CreateVolumeRequest %+v", req)
Copy link
Contributor

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

Copy link
Contributor Author

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


snapshotSource := csi.VolumeContentSource_Snapshot{
Snapshot: &csi.VolumeContentSource_SnapshotSource{
Id: snapContentObj.Spec.VolumeSnapshotSource.CSI.SnapshotHandle,
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

glog.V(5).Infof("VolumeContentSource_Snapshot %+v", snapshotSource)

if snapshotObj.Status.RestoreSize != nil {
capacity := options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: exists check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

volOpts controller.VolumeOptions
restoredVolSizeSmall bool
wrongDataSource bool
validSnapshotStatus bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: rename to snapshotStatusReady

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -511,6 +620,42 @@ func provisionMockServerSetupExpectations(identityServer *driver.MockIdentitySer
}, nil).Times(1)
}

func provisionFromSnapshotMockServerSetupExpectations(identityServer *driver.MockIdentityServer, controllerServer *driver.MockControllerServer) {
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments

}

// Setup mock call expectations.
if tc.wrongDataSource == false {
Copy link
Contributor

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

Copy link
Contributor Author

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.

if tc.wrongDataSource == false {
provisionFromSnapshotMockServerSetupExpectations(identityServer, controllerServer)
}
if tc.restoredVolSizeSmall == false && tc.wrongDataSource == false && tc.validSnapshotStatus {
Copy link
Contributor

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

Copy link
Contributor Author

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.

@@ -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 {
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

@xing-yang
Copy link
Contributor Author

@jingxu97 @davidz627 @lpabon Review comments are addressed. Can you please review again? Thanks!

@davidz627
Copy link
Contributor

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Sep 4, 2018
@lpabon
Copy link
Member

lpabon commented Sep 5, 2018

/lgtm
/approve

@k8s-ci-robot
Copy link
Contributor

[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 /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 5, 2018
@k8s-ci-robot k8s-ci-robot merged commit 265fecd into kubernetes-csi:master Sep 5, 2018
kbsonlong pushed a commit to kbsonlong/external-provisioner that referenced this pull request Dec 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants