Merge branch 'master' into status-52

This commit is contained in:
zhucan
2019-05-14 18:26:07 +08:00
committed by GitHub
45 changed files with 603 additions and 263 deletions

2
Gopkg.lock generated
View File

@@ -62,7 +62,6 @@
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp",
"ptypes/wrappers",
]
pruneopts = "NUT"
@@ -754,7 +753,6 @@
"github.com/container-storage-interface/spec/lib/go/csi",
"github.com/golang/mock/gomock",
"github.com/golang/protobuf/ptypes",
"github.com/golang/protobuf/ptypes/timestamp",
"github.com/kubernetes-csi/csi-lib-utils/connection",
"github.com/kubernetes-csi/csi-lib-utils/leaderelection",
"github.com/kubernetes-csi/csi-lib-utils/rpc",

View File

@@ -66,7 +66,7 @@ var (
snapshotNamePrefix = flag.String("snapshot-name-prefix", "snapshot", "Prefix to apply to the name of a created snapshot")
snapshotNameUUIDLength = flag.Int("snapshot-name-uuid-length", -1, "Length in characters for the generated uuid of a created snapshot. Defaults behavior is to NOT truncate.")
showVersion = flag.Bool("version", false, "Show version.")
csiTimeout = flag.Duration("timeout", defaultCSITimeout, "The timeout for any RPCs to the CSI driver. Default is 10s.")
csiTimeout = flag.Duration("timeout", defaultCSITimeout, "The timeout for any RPCs to the CSI driver. Default is 1 minute.")
leaderElection = flag.Bool("leader-election", false, "Enables leader election.")
leaderElectionNamespace = flag.String("leader-election-namespace", "", "The namespace where the leader election resource exists. Defaults to the pod namespace if not set.")
@@ -184,9 +184,9 @@ func main() {
snapClient,
kubeClient,
*snapshotterName,
factory.Volumesnapshot().V1alpha1().VolumeSnapshots(),
factory.Volumesnapshot().V1alpha1().VolumeSnapshotContents(),
factory.Volumesnapshot().V1alpha1().VolumeSnapshotClasses(),
factory.Snapshot().V1alpha1().VolumeSnapshots(),
factory.Snapshot().V1alpha1().VolumeSnapshotContents(),
factory.Snapshot().V1alpha1().VolumeSnapshotClasses(),
coreFactory.Core().V1().PersistentVolumeClaims(),
*createSnapshotContentRetryCount,
*createSnapshotContentInterval,

View File

@@ -25,7 +25,7 @@ rules:
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]

View File

@@ -72,7 +72,7 @@ spec:
serviceAccount: csi-snapshotter
containers:
- name: csi-provisioner
image: quay.io/k8scsi/csi-provisioner:v1.0.1
image: quay.io/k8scsi/csi-provisioner:v1.1.0
args:
- "--provisioner=csi-hostpath"
- "--csi-address=$(ADDRESS)"
@@ -85,7 +85,7 @@ spec:
- name: socket-dir
mountPath: /csi
- name: csi-snapshotter
image: quay.io/k8scsi/csi-snapshotter:v1.0.1
image: quay.io/k8scsi/csi-snapshotter:v1.1.0
args:
- "--csi-address=$(ADDRESS)"
- "--connection-timeout=15s"
@@ -98,7 +98,7 @@ spec:
- name: socket-dir
mountPath: /csi
- name: hostpath
image: quay.io/k8scsi/hostpathplugin:v1.0.1
image: quay.io/k8scsi/hostpathplugin:v1.1.0
args:
- "--v=5"
- "--endpoint=$(CSI_ENDPOINT)"

View File

@@ -15,5 +15,6 @@ limitations under the License.
*/
// +k8s:deepcopy-gen=package
// +groupName=snapshot.storage.k8s.io
package v1alpha1

View File

@@ -1,7 +1,7 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ limitations under the License.
package versioned
import (
volumesnapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1"
snapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1"
discovery "k8s.io/client-go/discovery"
rest "k8s.io/client-go/rest"
flowcontrol "k8s.io/client-go/util/flowcontrol"
@@ -27,27 +27,19 @@ import (
type Interface interface {
Discovery() discovery.DiscoveryInterface
VolumesnapshotV1alpha1() volumesnapshotv1alpha1.VolumesnapshotV1alpha1Interface
// Deprecated: please explicitly pick a version if possible.
Volumesnapshot() volumesnapshotv1alpha1.VolumesnapshotV1alpha1Interface
SnapshotV1alpha1() snapshotv1alpha1.SnapshotV1alpha1Interface
}
// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
*discovery.DiscoveryClient
volumesnapshotV1alpha1 *volumesnapshotv1alpha1.VolumesnapshotV1alpha1Client
snapshotV1alpha1 *snapshotv1alpha1.SnapshotV1alpha1Client
}
// VolumesnapshotV1alpha1 retrieves the VolumesnapshotV1alpha1Client
func (c *Clientset) VolumesnapshotV1alpha1() volumesnapshotv1alpha1.VolumesnapshotV1alpha1Interface {
return c.volumesnapshotV1alpha1
}
// Deprecated: Volumesnapshot retrieves the default version of VolumesnapshotClient.
// Please explicitly pick a version.
func (c *Clientset) Volumesnapshot() volumesnapshotv1alpha1.VolumesnapshotV1alpha1Interface {
return c.volumesnapshotV1alpha1
// SnapshotV1alpha1 retrieves the SnapshotV1alpha1Client
func (c *Clientset) SnapshotV1alpha1() snapshotv1alpha1.SnapshotV1alpha1Interface {
return c.snapshotV1alpha1
}
// Discovery retrieves the DiscoveryClient
@@ -66,7 +58,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
}
var cs Clientset
var err error
cs.volumesnapshotV1alpha1, err = volumesnapshotv1alpha1.NewForConfig(&configShallowCopy)
cs.snapshotV1alpha1, err = snapshotv1alpha1.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
}
@@ -82,7 +74,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *Clientset {
var cs Clientset
cs.volumesnapshotV1alpha1 = volumesnapshotv1alpha1.NewForConfigOrDie(c)
cs.snapshotV1alpha1 = snapshotv1alpha1.NewForConfigOrDie(c)
cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
return &cs
@@ -91,7 +83,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
// New creates a new Clientset for the given RESTClient.
func New(c rest.Interface) *Clientset {
var cs Clientset
cs.volumesnapshotV1alpha1 = volumesnapshotv1alpha1.New(c)
cs.snapshotV1alpha1 = snapshotv1alpha1.New(c)
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
return &cs

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@ package fake
import (
clientset "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned"
volumesnapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1"
fakevolumesnapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/fake"
snapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1"
fakesnapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/fake"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/discovery"
@@ -71,12 +71,7 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface {
var _ clientset.Interface = &Clientset{}
// VolumesnapshotV1alpha1 retrieves the VolumesnapshotV1alpha1Client
func (c *Clientset) VolumesnapshotV1alpha1() volumesnapshotv1alpha1.VolumesnapshotV1alpha1Interface {
return &fakevolumesnapshotv1alpha1.FakeVolumesnapshotV1alpha1{Fake: &c.Fake}
}
// Volumesnapshot retrieves the VolumesnapshotV1alpha1Client
func (c *Clientset) Volumesnapshot() volumesnapshotv1alpha1.VolumesnapshotV1alpha1Interface {
return &fakevolumesnapshotv1alpha1.FakeVolumesnapshotV1alpha1{Fake: &c.Fake}
// SnapshotV1alpha1 retrieves the SnapshotV1alpha1Client
func (c *Clientset) SnapshotV1alpha1() snapshotv1alpha1.SnapshotV1alpha1Interface {
return &fakesnapshotv1alpha1.FakeSnapshotV1alpha1{Fake: &c.Fake}
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ limitations under the License.
package fake
import (
volumesnapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1"
snapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -31,7 +31,7 @@ var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
var parameterCodec = runtime.NewParameterCodec(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
volumesnapshotv1alpha1.AddToScheme,
snapshotv1alpha1.AddToScheme,
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ limitations under the License.
package scheme
import (
volumesnapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1"
snapshotv1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -31,7 +31,7 @@ var Scheme = runtime.NewScheme()
var Codecs = serializer.NewCodecFactory(Scheme)
var ParameterCodec = runtime.NewParameterCodec(Scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
volumesnapshotv1alpha1.AddToScheme,
snapshotv1alpha1.AddToScheme,
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -30,13 +30,13 @@ import (
// FakeVolumeSnapshots implements VolumeSnapshotInterface
type FakeVolumeSnapshots struct {
Fake *FakeVolumesnapshotV1alpha1
Fake *FakeSnapshotV1alpha1
ns string
}
var volumesnapshotsResource = schema.GroupVersionResource{Group: "volumesnapshot", Version: "v1alpha1", Resource: "volumesnapshots"}
var volumesnapshotsResource = schema.GroupVersionResource{Group: "snapshot.storage.k8s.io", Version: "v1alpha1", Resource: "volumesnapshots"}
var volumesnapshotsKind = schema.GroupVersionKind{Group: "volumesnapshot", Version: "v1alpha1", Kind: "VolumeSnapshot"}
var volumesnapshotsKind = schema.GroupVersionKind{Group: "snapshot.storage.k8s.io", Version: "v1alpha1", Kind: "VolumeSnapshot"}
// Get takes name of the volumeSnapshot, and returns the corresponding volumeSnapshot object, and an error if there is any.
func (c *FakeVolumeSnapshots) Get(name string, options v1.GetOptions) (result *v1alpha1.VolumeSnapshot, err error) {

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -24,25 +24,25 @@ import (
testing "k8s.io/client-go/testing"
)
type FakeVolumesnapshotV1alpha1 struct {
type FakeSnapshotV1alpha1 struct {
*testing.Fake
}
func (c *FakeVolumesnapshotV1alpha1) VolumeSnapshots(namespace string) v1alpha1.VolumeSnapshotInterface {
func (c *FakeSnapshotV1alpha1) VolumeSnapshots(namespace string) v1alpha1.VolumeSnapshotInterface {
return &FakeVolumeSnapshots{c, namespace}
}
func (c *FakeVolumesnapshotV1alpha1) VolumeSnapshotClasses() v1alpha1.VolumeSnapshotClassInterface {
func (c *FakeSnapshotV1alpha1) VolumeSnapshotClasses() v1alpha1.VolumeSnapshotClassInterface {
return &FakeVolumeSnapshotClasses{c}
}
func (c *FakeVolumesnapshotV1alpha1) VolumeSnapshotContents() v1alpha1.VolumeSnapshotContentInterface {
func (c *FakeSnapshotV1alpha1) VolumeSnapshotContents() v1alpha1.VolumeSnapshotContentInterface {
return &FakeVolumeSnapshotContents{c}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeVolumesnapshotV1alpha1) RESTClient() rest.Interface {
func (c *FakeSnapshotV1alpha1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -30,12 +30,12 @@ import (
// FakeVolumeSnapshotClasses implements VolumeSnapshotClassInterface
type FakeVolumeSnapshotClasses struct {
Fake *FakeVolumesnapshotV1alpha1
Fake *FakeSnapshotV1alpha1
}
var volumesnapshotclassesResource = schema.GroupVersionResource{Group: "volumesnapshot", Version: "v1alpha1", Resource: "volumesnapshotclasses"}
var volumesnapshotclassesResource = schema.GroupVersionResource{Group: "snapshot.storage.k8s.io", Version: "v1alpha1", Resource: "volumesnapshotclasses"}
var volumesnapshotclassesKind = schema.GroupVersionKind{Group: "volumesnapshot", Version: "v1alpha1", Kind: "VolumeSnapshotClass"}
var volumesnapshotclassesKind = schema.GroupVersionKind{Group: "snapshot.storage.k8s.io", Version: "v1alpha1", Kind: "VolumeSnapshotClass"}
// Get takes name of the volumeSnapshotClass, and returns the corresponding volumeSnapshotClass object, and an error if there is any.
func (c *FakeVolumeSnapshotClasses) Get(name string, options v1.GetOptions) (result *v1alpha1.VolumeSnapshotClass, err error) {

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -30,12 +30,12 @@ import (
// FakeVolumeSnapshotContents implements VolumeSnapshotContentInterface
type FakeVolumeSnapshotContents struct {
Fake *FakeVolumesnapshotV1alpha1
Fake *FakeSnapshotV1alpha1
}
var volumesnapshotcontentsResource = schema.GroupVersionResource{Group: "volumesnapshot", Version: "v1alpha1", Resource: "volumesnapshotcontents"}
var volumesnapshotcontentsResource = schema.GroupVersionResource{Group: "snapshot.storage.k8s.io", Version: "v1alpha1", Resource: "volumesnapshotcontents"}
var volumesnapshotcontentsKind = schema.GroupVersionKind{Group: "volumesnapshot", Version: "v1alpha1", Kind: "VolumeSnapshotContent"}
var volumesnapshotcontentsKind = schema.GroupVersionKind{Group: "snapshot.storage.k8s.io", Version: "v1alpha1", Kind: "VolumeSnapshotContent"}
// Get takes name of the volumeSnapshotContent, and returns the corresponding volumeSnapshotContent object, and an error if there is any.
func (c *FakeVolumeSnapshotContents) Get(name string, options v1.GetOptions) (result *v1alpha1.VolumeSnapshotContent, err error) {

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -56,7 +56,7 @@ type volumeSnapshots struct {
}
// newVolumeSnapshots returns a VolumeSnapshots
func newVolumeSnapshots(c *VolumesnapshotV1alpha1Client, namespace string) *volumeSnapshots {
func newVolumeSnapshots(c *SnapshotV1alpha1Client, namespace string) *volumeSnapshots {
return &volumeSnapshots{
client: c.RESTClient(),
ns: namespace,

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -25,32 +25,32 @@ import (
rest "k8s.io/client-go/rest"
)
type VolumesnapshotV1alpha1Interface interface {
type SnapshotV1alpha1Interface interface {
RESTClient() rest.Interface
VolumeSnapshotsGetter
VolumeSnapshotClassesGetter
VolumeSnapshotContentsGetter
}
// VolumesnapshotV1alpha1Client is used to interact with features provided by the volumesnapshot group.
type VolumesnapshotV1alpha1Client struct {
// SnapshotV1alpha1Client is used to interact with features provided by the snapshot.storage.k8s.io group.
type SnapshotV1alpha1Client struct {
restClient rest.Interface
}
func (c *VolumesnapshotV1alpha1Client) VolumeSnapshots(namespace string) VolumeSnapshotInterface {
func (c *SnapshotV1alpha1Client) VolumeSnapshots(namespace string) VolumeSnapshotInterface {
return newVolumeSnapshots(c, namespace)
}
func (c *VolumesnapshotV1alpha1Client) VolumeSnapshotClasses() VolumeSnapshotClassInterface {
func (c *SnapshotV1alpha1Client) VolumeSnapshotClasses() VolumeSnapshotClassInterface {
return newVolumeSnapshotClasses(c)
}
func (c *VolumesnapshotV1alpha1Client) VolumeSnapshotContents() VolumeSnapshotContentInterface {
func (c *SnapshotV1alpha1Client) VolumeSnapshotContents() VolumeSnapshotContentInterface {
return newVolumeSnapshotContents(c)
}
// NewForConfig creates a new VolumesnapshotV1alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*VolumesnapshotV1alpha1Client, error) {
// NewForConfig creates a new SnapshotV1alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*SnapshotV1alpha1Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
@@ -59,12 +59,12 @@ func NewForConfig(c *rest.Config) (*VolumesnapshotV1alpha1Client, error) {
if err != nil {
return nil, err
}
return &VolumesnapshotV1alpha1Client{client}, nil
return &SnapshotV1alpha1Client{client}, nil
}
// NewForConfigOrDie creates a new VolumesnapshotV1alpha1Client for the given config and
// NewForConfigOrDie creates a new SnapshotV1alpha1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *VolumesnapshotV1alpha1Client {
func NewForConfigOrDie(c *rest.Config) *SnapshotV1alpha1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
@@ -72,9 +72,9 @@ func NewForConfigOrDie(c *rest.Config) *VolumesnapshotV1alpha1Client {
return client
}
// New creates a new VolumesnapshotV1alpha1Client for the given RESTClient.
func New(c rest.Interface) *VolumesnapshotV1alpha1Client {
return &VolumesnapshotV1alpha1Client{c}
// New creates a new SnapshotV1alpha1Client for the given RESTClient.
func New(c rest.Interface) *SnapshotV1alpha1Client {
return &SnapshotV1alpha1Client{c}
}
func setConfigDefaults(config *rest.Config) error {
@@ -92,7 +92,7 @@ func setConfigDefaults(config *rest.Config) error {
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *VolumesnapshotV1alpha1Client) RESTClient() rest.Interface {
func (c *SnapshotV1alpha1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ type volumeSnapshotClasses struct {
}
// newVolumeSnapshotClasses returns a VolumeSnapshotClasses
func newVolumeSnapshotClasses(c *VolumesnapshotV1alpha1Client) *volumeSnapshotClasses {
func newVolumeSnapshotClasses(c *SnapshotV1alpha1Client) *volumeSnapshotClasses {
return &volumeSnapshotClasses{
client: c.RESTClient(),
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ type volumeSnapshotContents struct {
}
// newVolumeSnapshotContents returns a VolumeSnapshotContents
func newVolumeSnapshotContents(c *VolumesnapshotV1alpha1Client) *volumeSnapshotContents {
func newVolumeSnapshotContents(c *SnapshotV1alpha1Client) *volumeSnapshotContents {
return &volumeSnapshotContents{
client: c.RESTClient(),
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -172,9 +172,9 @@ type SharedInformerFactory interface {
ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
Volumesnapshot() volumesnapshot.Interface
Snapshot() volumesnapshot.Interface
}
func (f *sharedInformerFactory) Volumesnapshot() volumesnapshot.Interface {
func (f *sharedInformerFactory) Snapshot() volumesnapshot.Interface {
return volumesnapshot.New(f, f.namespace, f.tweakListOptions)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -52,13 +52,13 @@ func (f *genericInformer) Lister() cache.GenericLister {
// TODO extend this to unknown resources with a client pool
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
switch resource {
// Group=volumesnapshot, Version=v1alpha1
// Group=snapshot.storage.k8s.io, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithResource("volumesnapshots"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Volumesnapshot().V1alpha1().VolumeSnapshots().Informer()}, nil
return &genericInformer{resource: resource.GroupResource(), informer: f.Snapshot().V1alpha1().VolumeSnapshots().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("volumesnapshotclasses"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Volumesnapshot().V1alpha1().VolumeSnapshotClasses().Informer()}, nil
return &genericInformer{resource: resource.GroupResource(), informer: f.Snapshot().V1alpha1().VolumeSnapshotClasses().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("volumesnapshotcontents"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Volumesnapshot().V1alpha1().VolumeSnapshotContents().Informer()}, nil
return &genericInformer{resource: resource.GroupResource(), informer: f.Snapshot().V1alpha1().VolumeSnapshotContents().Informer()}, nil
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@ limitations under the License.
// Code generated by informer-gen. DO NOT EDIT.
package volumesnapshot
package snapshot
import (
internalinterfaces "github.com/kubernetes-csi/external-snapshotter/pkg/client/informers/externalversions/internalinterfaces"

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -61,13 +61,13 @@ func NewFilteredVolumeSnapshotInformer(client versioned.Interface, namespace str
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VolumesnapshotV1alpha1().VolumeSnapshots(namespace).List(options)
return client.SnapshotV1alpha1().VolumeSnapshots(namespace).List(options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VolumesnapshotV1alpha1().VolumeSnapshots(namespace).Watch(options)
return client.SnapshotV1alpha1().VolumeSnapshots(namespace).Watch(options)
},
},
&volumesnapshotv1alpha1.VolumeSnapshot{},

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -60,13 +60,13 @@ func NewFilteredVolumeSnapshotClassInformer(client versioned.Interface, resyncPe
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VolumesnapshotV1alpha1().VolumeSnapshotClasses().List(options)
return client.SnapshotV1alpha1().VolumeSnapshotClasses().List(options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VolumesnapshotV1alpha1().VolumeSnapshotClasses().Watch(options)
return client.SnapshotV1alpha1().VolumeSnapshotClasses().Watch(options)
},
},
&volumesnapshotv1alpha1.VolumeSnapshotClass{},

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -60,13 +60,13 @@ func NewFilteredVolumeSnapshotContentInformer(client versioned.Interface, resync
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VolumesnapshotV1alpha1().VolumeSnapshotContents().List(options)
return client.SnapshotV1alpha1().VolumeSnapshotContents().List(options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.VolumesnapshotV1alpha1().VolumeSnapshotContents().Watch(options)
return client.SnapshotV1alpha1().VolumeSnapshotContents().Watch(options)
},
},
&volumesnapshotv1alpha1.VolumeSnapshotContent{},

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -30,9 +30,9 @@ import (
// Handler is responsible for handling VolumeSnapshot events from informer.
type Handler interface {
CreateSnapshot(snapshot *crdv1.VolumeSnapshot, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (string, string, int64, int64, bool, error)
CreateSnapshot(snapshot *crdv1.VolumeSnapshot, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (string, string, time.Time, int64, bool, error)
DeleteSnapshot(content *crdv1.VolumeSnapshotContent, snapshotterCredentials map[string]string) error
GetSnapshotStatus(content *crdv1.VolumeSnapshotContent) (bool, int64, int64, error)
GetSnapshotStatus(content *crdv1.VolumeSnapshotContent) (bool, time.Time, int64, error)
}
// csiHandler is a handler that calls CSI to create/delete volume snapshot.
@@ -58,18 +58,18 @@ func NewCSIHandler(
}
}
func (handler *csiHandler) CreateSnapshot(snapshot *crdv1.VolumeSnapshot, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (string, string, int64, int64, bool, error) {
func (handler *csiHandler) CreateSnapshot(snapshot *crdv1.VolumeSnapshot, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (string, string, time.Time, int64, bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), handler.timeout)
defer cancel()
snapshotName, err := makeSnapshotName(handler.snapshotNamePrefix, string(snapshot.UID), handler.snapshotNameUUIDLength)
if err != nil {
return "", "", 0, 0, false, err
return "", "", time.Time{}, 0, false, err
}
newParameters, err := removePrefixedParameters(parameters)
if err != nil {
return "", "", 0, 0, false, fmt.Errorf("failed to remove CSI Parameters of prefixed keys: %v", err)
return "", "", time.Time{}, 0, false, fmt.Errorf("failed to remove CSI Parameters of prefixed keys: %v", err)
}
return handler.snapshotter.CreateSnapshot(ctx, snapshotName, volume, newParameters, snapshotterCredentials)
}
@@ -89,16 +89,16 @@ func (handler *csiHandler) DeleteSnapshot(content *crdv1.VolumeSnapshotContent,
return nil
}
func (handler *csiHandler) GetSnapshotStatus(content *crdv1.VolumeSnapshotContent) (bool, int64, int64, error) {
func (handler *csiHandler) GetSnapshotStatus(content *crdv1.VolumeSnapshotContent) (bool, time.Time, int64, error) {
if content.Spec.CSI == nil {
return false, 0, 0, fmt.Errorf("CSISnapshot not defined in spec")
return false, time.Time{}, 0, fmt.Errorf("CSISnapshot not defined in spec")
}
ctx, cancel := context.WithTimeout(context.Background(), handler.timeout)
defer cancel()
csiSnapshotStatus, timestamp, size, err := handler.snapshotter.GetSnapshotStatus(ctx, content.Spec.CSI.SnapshotHandle)
if err != nil {
return false, 0, 0, fmt.Errorf("failed to list snapshot content %s: %q", content.Name, err)
return false, time.Time{}, 0, fmt.Errorf("failed to list snapshot content %s: %q", content.Name, err)
}
return csiSnapshotStatus, timestamp, size, nil

View File

@@ -21,6 +21,7 @@ import (
"errors"
"fmt"
"reflect"
sysruntime "runtime"
"strconv"
"strings"
"sync"
@@ -53,6 +54,7 @@ import (
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/util/slice"
)
// This is a unit test framework for snapshot controller.
@@ -111,6 +113,7 @@ type controllerTest struct {
expectedListCalls []listCall
// Function to call as the test.
test testCall
expectSuccess bool
}
type testCall func(ctrl *csiSnapshotController, reactor *snapshotReactor, test controllerTest) error
@@ -177,6 +180,11 @@ func withContentFinalizer(content *crdv1.VolumeSnapshotContent) *crdv1.VolumeSna
return content
}
func withPVCFinalizer(pvc *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim {
pvc.ObjectMeta.Finalizers = append(pvc.ObjectMeta.Finalizers, PVCFinalizer)
return pvc
}
// React is a callback called by fake kubeClient from the controller.
// In other words, every snapshot/content change performed by the controller ends
// here.
@@ -331,6 +339,32 @@ func (r *snapshotReactor) React(action core.Action) (handled bool, ret runtime.O
klog.V(4).Infof("GetClaim: claim %s not found", name)
return true, nil, fmt.Errorf("cannot find claim %s", name)
case action.Matches("update", "persistentvolumeclaims"):
obj := action.(core.UpdateAction).GetObject()
claim := obj.(*v1.PersistentVolumeClaim)
// Check and bump object version
storedClaim, found := r.claims[claim.Name]
if found {
storedVer, _ := strconv.Atoi(storedClaim.ResourceVersion)
requestedVer, _ := strconv.Atoi(claim.ResourceVersion)
if storedVer != requestedVer {
return true, obj, errVersionConflict
}
// Don't modify the existing object
claim = claim.DeepCopy()
claim.ResourceVersion = strconv.Itoa(storedVer + 1)
} else {
return true, nil, fmt.Errorf("cannot update claim %s: claim not found", claim.Name)
}
// Store the updated object to appropriate places.
r.claims[claim.Name] = claim
r.changedObjects = append(r.changedObjects, claim)
r.changedSinceLastSync++
klog.V(4).Infof("saved updated claim %s", claim.Name)
return true, claim, nil
case action.Matches("get", "storageclasses"):
name := action.(core.GetAction).GetName()
storageClass, found := r.storageClasses[name]
@@ -550,6 +584,9 @@ func (r *snapshotReactor) syncAll() {
for _, v := range r.contents {
r.changedObjects = append(r.changedObjects, v)
}
for _, pvc := range r.claims {
r.changedObjects = append(r.changedObjects, pvc)
}
r.changedSinceLastSync = 0
}
@@ -699,6 +736,7 @@ func newSnapshotReactor(kubeClient *kubefake.Clientset, client *fake.Clientset,
client.AddReactor("delete", "volumesnapshotcontents", reactor.React)
client.AddReactor("delete", "volumesnapshots", reactor.React)
kubeClient.AddReactor("get", "persistentvolumeclaims", reactor.React)
kubeClient.AddReactor("update", "persistentvolumeclaims", reactor.React)
kubeClient.AddReactor("get", "persistentvolumes", reactor.React)
kubeClient.AddReactor("get", "storageclasses", reactor.React)
kubeClient.AddReactor("get", "secrets", reactor.React)
@@ -728,9 +766,9 @@ func newTestController(kubeClient kubernetes.Interface, clientset clientset.Inte
clientset,
kubeClient,
mockDriverName,
informerFactory.Volumesnapshot().V1alpha1().VolumeSnapshots(),
informerFactory.Volumesnapshot().V1alpha1().VolumeSnapshotContents(),
informerFactory.Volumesnapshot().V1alpha1().VolumeSnapshotClasses(),
informerFactory.Snapshot().V1alpha1().VolumeSnapshots(),
informerFactory.Snapshot().V1alpha1().VolumeSnapshotContents(),
informerFactory.Snapshot().V1alpha1().VolumeSnapshotClasses(),
coreFactory.Core().V1().PersistentVolumeClaims(),
3,
5*time.Millisecond,
@@ -746,6 +784,7 @@ func newTestController(kubeClient kubernetes.Interface, clientset clientset.Inte
ctrl.contentListerSynced = alwaysReady
ctrl.snapshotListerSynced = alwaysReady
ctrl.classListerSynced = alwaysReady
ctrl.pvcListerSynced = alwaysReady
return ctrl, nil
}
@@ -845,7 +884,7 @@ func newSnapshotArray(name, className, boundToContent, snapshotUID, claimName st
}
// newClaim returns a new claim with given attributes
func newClaim(name, claimUID, capacity, boundToVolume string, phase v1.PersistentVolumeClaimPhase, class *string) *v1.PersistentVolumeClaim {
func newClaim(name, claimUID, capacity, boundToVolume string, phase v1.PersistentVolumeClaimPhase, class *string, bFinalizer bool) *v1.PersistentVolumeClaim {
claim := v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: name,
@@ -877,6 +916,9 @@ func newClaim(name, claimUID, capacity, boundToVolume string, phase v1.Persisten
claim.Status.Capacity = claim.Spec.Resources.Requests
}
if bFinalizer {
return withPVCFinalizer(&claim)
}
return &claim
}
@@ -884,7 +926,15 @@ func newClaim(name, claimUID, capacity, boundToVolume string, phase v1.Persisten
// newClaim() with the same parameters.
func newClaimArray(name, claimUID, capacity, boundToVolume string, phase v1.PersistentVolumeClaimPhase, class *string) []*v1.PersistentVolumeClaim {
return []*v1.PersistentVolumeClaim{
newClaim(name, claimUID, capacity, boundToVolume, phase, class),
newClaim(name, claimUID, capacity, boundToVolume, phase, class, false),
}
}
// newClaimArrayFinalizer returns array with a single claim that would be returned by
// newClaim() with the same parameters plus finalizer.
func newClaimArrayFinalizer(name, claimUID, capacity, boundToVolume string, phase v1.PersistentVolumeClaimPhase, class *string) []*v1.PersistentVolumeClaim {
return []*v1.PersistentVolumeClaim{
newClaim(name, claimUID, capacity, boundToVolume, phase, class, true),
}
}
@@ -961,6 +1011,14 @@ func testSyncContent(ctrl *csiSnapshotController, reactor *snapshotReactor, test
return ctrl.syncContent(test.initialContents[0])
}
func testAddPVCFinalizer(ctrl *csiSnapshotController, reactor *snapshotReactor, test controllerTest) error {
return ctrl.ensureSnapshotSourceFinalizer(test.initialSnapshots[0])
}
func testRemovePVCFinalizer(ctrl *csiSnapshotController, reactor *snapshotReactor, test controllerTest) error {
return ctrl.checkandRemoveSnapshotSourceFinalizer(test.initialSnapshots[0])
}
var (
classEmpty string
classGold = "gold"
@@ -1097,6 +1155,113 @@ func runSyncTests(t *testing.T, tests []controllerTest, snapshotClasses []*crdv1
}
}
// This tests ensureSnapshotSourceFinalizer and checkandRemoveSnapshotSourceFinalizer
func runPVCFinalizerTests(t *testing.T, tests []controllerTest, snapshotClasses []*crdv1.VolumeSnapshotClass) {
snapshotscheme.AddToScheme(scheme.Scheme)
for _, test := range tests {
klog.V(4).Infof("starting test %q", test.name)
// Initialize the controller
kubeClient := &kubefake.Clientset{}
client := &fake.Clientset{}
ctrl, err := newTestController(kubeClient, client, nil, t, test)
if err != nil {
t.Fatalf("Test %q construct persistent content failed: %v", test.name, err)
}
reactor := newSnapshotReactor(kubeClient, client, ctrl, nil, nil, test.errors)
for _, snapshot := range test.initialSnapshots {
ctrl.snapshotStore.Add(snapshot)
reactor.snapshots[snapshot.Name] = snapshot
}
for _, content := range test.initialContents {
if ctrl.isDriverMatch(test.initialContents[0]) {
ctrl.contentStore.Add(content)
reactor.contents[content.Name] = content
}
}
pvcIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
for _, claim := range test.initialClaims {
reactor.claims[claim.Name] = claim
pvcIndexer.Add(claim)
}
ctrl.pvcLister = corelisters.NewPersistentVolumeClaimLister(pvcIndexer)
for _, volume := range test.initialVolumes {
reactor.volumes[volume.Name] = volume
}
for _, storageClass := range test.initialStorageClasses {
reactor.storageClasses[storageClass.Name] = storageClass
}
for _, secret := range test.initialSecrets {
reactor.secrets[secret.Name] = secret
}
// Inject classes into controller via a custom lister.
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
for _, class := range snapshotClasses {
indexer.Add(class)
}
ctrl.classLister = storagelisters.NewVolumeSnapshotClassLister(indexer)
// Run the tested functions
err = test.test(ctrl, reactor, test)
if err != nil {
t.Errorf("Test %q failed: %v", test.name, err)
}
// Verify PVCFinalizer tests results
evaluatePVCFinalizerTests(ctrl, reactor, test, t)
}
}
// Evaluate PVCFinalizer tests results
func evaluatePVCFinalizerTests(ctrl *csiSnapshotController, reactor *snapshotReactor, test controllerTest, t *testing.T) {
// Evaluate results
bHasPVCFinalizer := false
name := sysruntime.FuncForPC(reflect.ValueOf(test.test).Pointer()).Name()
index := strings.LastIndex(name, ".")
if index == -1 {
t.Errorf("Test %q: failed to test finalizer - invalid test call name [%s]", test.name, name)
return
}
names := []rune(name)
funcName := string(names[index+1 : len(name)])
klog.V(4).Infof("test %q: PVCFinalizer test func name: [%s]", test.name, funcName)
if funcName == "testAddPVCFinalizer" {
for _, pvc := range reactor.claims {
if test.initialClaims[0].Name == pvc.Name {
if !slice.ContainsString(test.initialClaims[0].ObjectMeta.Finalizers, PVCFinalizer, nil) && slice.ContainsString(pvc.ObjectMeta.Finalizers, PVCFinalizer, nil) {
klog.V(4).Infof("test %q succeeded. PVCFinalizer is added to PVC %s", test.name, pvc.Name)
bHasPVCFinalizer = true
}
break
}
}
if test.expectSuccess && !bHasPVCFinalizer {
t.Errorf("Test %q: failed to add finalizer to PVC %s", test.name, test.initialClaims[0].Name)
}
}
bHasPVCFinalizer = true
if funcName == "testRemovePVCFinalizer" {
for _, pvc := range reactor.claims {
if test.initialClaims[0].Name == pvc.Name {
if slice.ContainsString(test.initialClaims[0].ObjectMeta.Finalizers, PVCFinalizer, nil) && !slice.ContainsString(pvc.ObjectMeta.Finalizers, PVCFinalizer, nil) {
klog.V(4).Infof("test %q succeeded. PVCFinalizer is removed from PVC %s", test.name, pvc.Name)
bHasPVCFinalizer = false
}
break
}
}
if test.expectSuccess && bHasPVCFinalizer {
t.Errorf("Test %q: failed to remove finalizer from PVC %s", test.name, test.initialClaims[0].Name)
}
}
}
func getSize(size int64) *resource.Quantity {
return resource.NewQuantity(size, resource.BinarySI)
}
@@ -1126,7 +1291,7 @@ type listCall struct {
snapshotID string
// information to return
readyToUse bool
createTime int64
createTime time.Time
size int64
err error
}
@@ -1146,7 +1311,7 @@ type createCall struct {
// information to return
driverName string
snapshotId string
timestamp int64
creationTime time.Time
size int64
readyToUse bool
err error
@@ -1164,10 +1329,10 @@ type fakeSnapshotter struct {
t *testing.T
}
func (f *fakeSnapshotter) CreateSnapshot(ctx context.Context, snapshotName string, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (string, string, int64, int64, bool, error) {
func (f *fakeSnapshotter) CreateSnapshot(ctx context.Context, snapshotName string, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (string, string, time.Time, int64, bool, error) {
if f.createCallCounter >= len(f.createCalls) {
f.t.Errorf("Unexpected CSI Create Snapshot call: snapshotName=%s, volume=%v, index: %d, calls: %+v", snapshotName, volume.Name, f.createCallCounter, f.createCalls)
return "", "", 0, 0, false, fmt.Errorf("unexpected call")
return "", "", time.Time{}, 0, false, fmt.Errorf("unexpected call")
}
call := f.createCalls[f.createCallCounter]
f.createCallCounter++
@@ -1194,10 +1359,10 @@ func (f *fakeSnapshotter) CreateSnapshot(ctx context.Context, snapshotName strin
}
if err != nil {
return "", "", 0, 0, false, fmt.Errorf("unexpected call")
return "", "", time.Time{}, 0, false, fmt.Errorf("unexpected call")
}
return call.driverName, call.snapshotId, call.timestamp, call.size, call.readyToUse, call.err
return call.driverName, call.snapshotId, call.creationTime, call.size, call.readyToUse, call.err
}
func (f *fakeSnapshotter) DeleteSnapshot(ctx context.Context, snapshotID string, snapshotterCredentials map[string]string) error {
@@ -1226,10 +1391,10 @@ func (f *fakeSnapshotter) DeleteSnapshot(ctx context.Context, snapshotID string,
return call.err
}
func (f *fakeSnapshotter) GetSnapshotStatus(ctx context.Context, snapshotID string) (bool, int64, int64, error) {
func (f *fakeSnapshotter) GetSnapshotStatus(ctx context.Context, snapshotID string) (bool, time.Time, int64, error) {
if f.listCallCounter >= len(f.listCalls) {
f.t.Errorf("Unexpected CSI list Snapshot call: snapshotID=%s, index: %d, calls: %+v", snapshotID, f.createCallCounter, f.createCalls)
return false, 0, 0, fmt.Errorf("unexpected call")
return false, time.Time{}, 0, fmt.Errorf("unexpected call")
}
call := f.listCalls[f.listCallCounter]
f.listCallCounter++
@@ -1241,7 +1406,7 @@ func (f *fakeSnapshotter) GetSnapshotStatus(ctx context.Context, snapshotID stri
}
if err != nil {
return false, 0, 0, fmt.Errorf("unexpected call")
return false, time.Time{}, 0, fmt.Errorf("unexpected call")
}
return call.readyToUse, call.createTime, call.size, call.err

View File

@@ -192,11 +192,19 @@ func (ctrl *csiSnapshotController) syncSnapshot(snapshot *crdv1.VolumeSnapshot)
return ctrl.addSnapshotFinalizer(snapshot)
}
klog.V(5).Infof("syncSnapshot[%s]: check if we should remove finalizer on snapshot source and remove it if we can", snapshotKey(snapshot))
// Check if we should remove finalizer on snapshot source and remove it if we can.
errFinalizer := ctrl.checkandRemoveSnapshotSourceFinalizer(snapshot)
if errFinalizer != nil {
klog.Errorf("error check and remove snapshot source finalizer for snapshot [%s]: %v", snapshot.Name, errFinalizer)
// Log an event and keep the original error from syncUnready/ReadySnapshot
ctrl.eventRecorder.Event(snapshot, v1.EventTypeWarning, "ErrorSnapshotSourceFinalizer", "Error check and remove PVC Finalizer for VolumeSnapshot")
}
if !snapshot.Status.ReadyToUse {
return ctrl.syncUnreadySnapshot(snapshot)
}
return ctrl.syncReadySnapshot(snapshot)
}
// syncReadySnapshot checks the snapshot which has been bound to snapshot content successfully before.
@@ -367,7 +375,6 @@ func (ctrl *csiSnapshotController) createSnapshot(snapshot *crdv1.VolumeSnapshot
// We will get an "snapshot update" event soon, this is not a big error
klog.V(4).Infof("createSnapshot [%s]: cannot update internal cache: %v", snapshotKey(snapshotObj), updateErr)
}
return nil
})
return nil
@@ -451,7 +458,7 @@ func IsSnapshotBound(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapsh
// isSnapshotConentBeingUsed checks if snapshot content is bound to snapshot.
func (ctrl *csiSnapshotController) isSnapshotContentBeingUsed(content *crdv1.VolumeSnapshotContent) bool {
if content.Spec.VolumeSnapshotRef != nil {
snapshotObj, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(content.Spec.VolumeSnapshotRef.Namespace).Get(content.Spec.VolumeSnapshotRef.Name, metav1.GetOptions{})
snapshotObj, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshots(content.Spec.VolumeSnapshotRef.Namespace).Get(content.Spec.VolumeSnapshotRef.Name, metav1.GetOptions{})
if err != nil {
klog.Infof("isSnapshotContentBeingUsed: Cannot get snapshot %s from api server: [%v]. VolumeSnapshot object may be deleted already.", content.Spec.VolumeSnapshotRef.Name, err)
return false
@@ -503,7 +510,7 @@ func (ctrl *csiSnapshotController) checkandBindSnapshotContent(snapshot *crdv1.V
contentClone.Spec.VolumeSnapshotRef.UID = snapshot.UID
className := *(snapshot.Spec.VolumeSnapshotClassName)
contentClone.Spec.VolumeSnapshotClassName = &className
newContent, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
newContent, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
if err != nil {
klog.V(4).Infof("updating VolumeSnapshotContent[%s] error status failed %v", newContent.Name, err)
return nil, err
@@ -556,7 +563,7 @@ func (ctrl *csiSnapshotController) getCreateSnapshotInput(snapshot *crdv1.Volume
func (ctrl *csiSnapshotController) checkandUpdateBoundSnapshotStatusOperation(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapshotContent) (*crdv1.VolumeSnapshot, error) {
var err error
var timestamp int64
var creationTime time.Time
var size int64
var readyToUse = false
var driverName string
@@ -564,7 +571,7 @@ func (ctrl *csiSnapshotController) checkandUpdateBoundSnapshotStatusOperation(sn
if snapshot.Spec.Source == nil {
klog.V(5).Infof("checkandUpdateBoundSnapshotStatusOperation: checking whether snapshot [%s] is pre-bound to content [%s]", snapshot.Name, content.Name)
readyToUse, timestamp, size, err = ctrl.handler.GetSnapshotStatus(content)
readyToUse, creationTime, size, err = ctrl.handler.GetSnapshotStatus(content)
if err != nil {
klog.Errorf("checkandUpdateBoundSnapshotStatusOperation: failed to call get snapshot status to check whether snapshot is ready to use %q", err)
return nil, err
@@ -577,18 +584,18 @@ func (ctrl *csiSnapshotController) checkandUpdateBoundSnapshotStatusOperation(sn
if err != nil {
return nil, fmt.Errorf("failed to get input parameters to create snapshot %s: %q", snapshot.Name, err)
}
driverName, snapshotID, timestamp, size, readyToUse, err = ctrl.handler.CreateSnapshot(snapshot, volume, class.Parameters, snapshotterCredentials)
driverName, snapshotID, creationTime, size, readyToUse, err = ctrl.handler.CreateSnapshot(snapshot, volume, class.Parameters, snapshotterCredentials)
if err != nil {
klog.Errorf("checkandUpdateBoundSnapshotStatusOperation: failed to call create snapshot to check whether the snapshot is ready to use %q", err)
return nil, err
}
}
klog.V(5).Infof("checkandUpdateBoundSnapshotStatusOperation: driver %s, snapshotId %s, timestamp %d, size %d, readyToUse %t", driverName, snapshotID, timestamp, size, readyToUse)
klog.V(5).Infof("checkandUpdateBoundSnapshotStatusOperation: driver %s, snapshotId %s, creationTime %v, size %d, readyToUse %t", driverName, snapshotID, creationTime, size, readyToUse)
if timestamp == 0 {
timestamp = time.Now().UnixNano()
if creationTime.IsZero() {
creationTime = time.Now()
}
newSnapshot, err := ctrl.updateSnapshotStatus(snapshot, readyToUse, timestamp, size, IsSnapshotBound(snapshot, content))
newSnapshot, err := ctrl.updateSnapshotStatus(snapshot, readyToUse, creationTime, size, IsSnapshotBound(snapshot, content))
if err != nil {
return nil, err
}
@@ -612,22 +619,31 @@ func (ctrl *csiSnapshotController) createSnapshotOperation(snapshot *crdv1.Volum
return snapshot, nil
}
// If PVC is not being deleted and finalizer is not added yet, a finalizer should be added.
klog.V(5).Infof("createSnapshotOperation: Check if PVC is not being deleted and add Finalizer for source of snapshot [%s] if needed", snapshot.Name)
err := ctrl.ensureSnapshotSourceFinalizer(snapshot)
if err != nil {
klog.Errorf("createSnapshotOperation failed to add finalizer for source of snapshot %s", err)
return nil, err
}
class, volume, contentName, snapshotterCredentials, err := ctrl.getCreateSnapshotInput(snapshot)
if err != nil {
return nil, fmt.Errorf("failed to get input parameters to create snapshot %s: %q", snapshot.Name, err)
}
driverName, snapshotID, timestamp, size, readyToUse, err := ctrl.handler.CreateSnapshot(snapshot, volume, class.Parameters, snapshotterCredentials)
driverName, snapshotID, creationTime, size, readyToUse, err := ctrl.handler.CreateSnapshot(snapshot, volume, class.Parameters, snapshotterCredentials)
if err != nil {
return nil, fmt.Errorf("failed to take snapshot of the volume, %s: %q", volume.Name, err)
}
klog.V(5).Infof("Created snapshot: driver %s, snapshotId %s, timestamp %d, size %d, readyToUse %t", driverName, snapshotID, timestamp, size, readyToUse)
klog.V(5).Infof("Created snapshot: driver %s, snapshotId %s, creationTime %v, size %d, readyToUse %t", driverName, snapshotID, creationTime, size, readyToUse)
var newSnapshot *crdv1.VolumeSnapshot
// Update snapshot status with timestamp
// Update snapshot status with creationTime
for i := 0; i < ctrl.createSnapshotContentRetryCount; i++ {
klog.V(5).Infof("createSnapshot [%s]: trying to update snapshot creation timestamp", snapshotKey(snapshot))
newSnapshot, err = ctrl.updateSnapshotStatus(snapshot, readyToUse, timestamp, size, false)
newSnapshot, err = ctrl.updateSnapshotStatus(snapshot, readyToUse, creationTime, size, false)
if err == nil {
break
}
@@ -651,6 +667,7 @@ func (ctrl *csiSnapshotController) createSnapshotOperation(snapshot *crdv1.Volum
class.DeletionPolicy = new(crdv1.DeletionPolicy)
*class.DeletionPolicy = crdv1.VolumeSnapshotContentDelete
}
timestamp := creationTime.UnixNano()
snapshotContent := &crdv1.VolumeSnapshotContent{
ObjectMeta: metav1.ObjectMeta{
Name: contentName,
@@ -674,7 +691,7 @@ func (ctrl *csiSnapshotController) createSnapshotOperation(snapshot *crdv1.Volum
// Try to create the VolumeSnapshotContent object several times
for i := 0; i < ctrl.createSnapshotContentRetryCount; i++ {
klog.V(5).Infof("createSnapshot [%s]: trying to save volume snapshot content %s", snapshotKey(snapshot), snapshotContent.Name)
if _, err = ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Create(snapshotContent); err == nil || apierrs.IsAlreadyExists(err) {
if _, err = ctrl.clientset.SnapshotV1alpha1().VolumeSnapshotContents().Create(snapshotContent); err == nil || apierrs.IsAlreadyExists(err) {
// Save succeeded.
if err != nil {
klog.V(3).Infof("volume snapshot content %q for snapshot %q already exists, reusing", snapshotContent.Name, snapshotKey(snapshot))
@@ -741,7 +758,7 @@ func (ctrl *csiSnapshotController) deleteSnapshotContentOperation(content *crdv1
return fmt.Errorf("failed to delete snapshot %#v, err: %v", content.Name, err)
}
err = ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Delete(content.Name, &metav1.DeleteOptions{})
err = ctrl.clientset.SnapshotV1alpha1().VolumeSnapshotContents().Delete(content.Name, &metav1.DeleteOptions{})
if err != nil {
ctrl.eventRecorder.Event(content, v1.EventTypeWarning, "SnapshotContentObjectDeleteError", "Failed to delete snapshot content API object")
return fmt.Errorf("failed to delete VolumeSnapshotContent %s from API server: %q", content.Name, err)
@@ -752,7 +769,7 @@ func (ctrl *csiSnapshotController) deleteSnapshotContentOperation(content *crdv1
func (ctrl *csiSnapshotController) bindandUpdateVolumeSnapshot(snapshotContent *crdv1.VolumeSnapshotContent, snapshot *crdv1.VolumeSnapshot) (*crdv1.VolumeSnapshot, error) {
klog.V(5).Infof("bindandUpdateVolumeSnapshot for snapshot [%s]: snapshotContent [%s]", snapshot.Name, snapshotContent.Name)
snapshotObj, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshot.Namespace).Get(snapshot.Name, metav1.GetOptions{})
snapshotObj, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshots(snapshot.Namespace).Get(snapshot.Name, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("error get snapshot %s from api server: %v", snapshotKey(snapshot), err)
}
@@ -765,7 +782,7 @@ func (ctrl *csiSnapshotController) bindandUpdateVolumeSnapshot(snapshotContent *
} else {
klog.Infof("bindVolumeSnapshotContentToVolumeSnapshot: before bind VolumeSnapshot %s to volumeSnapshotContent [%s]", snapshot.Name, snapshotContent.Name)
snapshotCopy.Spec.SnapshotContentName = snapshotContent.Name
updateSnapshot, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshot.Namespace).Update(snapshotCopy)
updateSnapshot, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshots(snapshot.Namespace).Update(snapshotCopy)
if err != nil {
klog.Infof("bindVolumeSnapshotContentToVolumeSnapshot: Error binding VolumeSnapshot %s to volumeSnapshotContent [%s]. Error [%#v]", snapshot.Name, snapshotContent.Name, err)
return nil, newControllerUpdateError(snapshotKey(snapshot), err.Error())
@@ -791,7 +808,7 @@ func (ctrl *csiSnapshotController) updateSnapshotContentSize(content *crdv1.Volu
}
contentClone := content.DeepCopy()
contentClone.Spec.VolumeSnapshotSource.CSI.RestoreSize = &size
_, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
_, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
if err != nil {
return newControllerUpdateError(content.Name, err.Error())
}
@@ -804,12 +821,12 @@ func (ctrl *csiSnapshotController) updateSnapshotContentSize(content *crdv1.Volu
}
// UpdateSnapshotStatus converts snapshot status to crdv1.VolumeSnapshotCondition
func (ctrl *csiSnapshotController) updateSnapshotStatus(snapshot *crdv1.VolumeSnapshot, readyToUse bool, createdAt, size int64, bound bool) (*crdv1.VolumeSnapshot, error) {
func (ctrl *csiSnapshotController) updateSnapshotStatus(snapshot *crdv1.VolumeSnapshot, readyToUse bool, createdAt time.Time, size int64, bound bool) (*crdv1.VolumeSnapshot, error) {
klog.V(5).Infof("updating VolumeSnapshot[]%s, readyToUse %v, timestamp %v", snapshotKey(snapshot), readyToUse, createdAt)
status := snapshot.Status
change := false
timeAt := &metav1.Time{
Time: time.Unix(0, createdAt),
Time: createdAt,
}
snapshotClone := snapshot.DeepCopy()
@@ -932,7 +949,7 @@ func (ctrl *csiSnapshotController) SetDefaultSnapshotClass(snapshot *crdv1.Volum
klog.V(5).Infof("setDefaultSnapshotClass [%s]: default VolumeSnapshotClassName [%s]", snapshot.Name, defaultClasses[0].Name)
snapshotClone := snapshot.DeepCopy()
snapshotClone.Spec.VolumeSnapshotClassName = &(defaultClasses[0].Name)
newSnapshot, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone)
newSnapshot, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone)
if err != nil {
klog.V(4).Infof("updating VolumeSnapshot[%s] default class failed %v", snapshotKey(snapshot), err)
}
@@ -999,7 +1016,7 @@ func (ctrl *csiSnapshotController) addContentFinalizer(content *crdv1.VolumeSnap
contentClone := content.DeepCopy()
contentClone.ObjectMeta.Finalizers = append(contentClone.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer)
_, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
_, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
if err != nil {
return newControllerUpdateError(content.Name, err.Error())
}
@@ -1018,7 +1035,7 @@ func (ctrl *csiSnapshotController) removeContentFinalizer(content *crdv1.VolumeS
contentClone := content.DeepCopy()
contentClone.ObjectMeta.Finalizers = slice.RemoveString(contentClone.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer, nil)
_, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
_, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
if err != nil {
return newControllerUpdateError(content.Name, err.Error())
}
@@ -1036,7 +1053,7 @@ func (ctrl *csiSnapshotController) removeContentFinalizer(content *crdv1.VolumeS
func (ctrl *csiSnapshotController) addSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot) error {
snapshotClone := snapshot.DeepCopy()
snapshotClone.ObjectMeta.Finalizers = append(snapshotClone.ObjectMeta.Finalizers, VolumeSnapshotFinalizer)
_, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone)
_, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone)
if err != nil {
return newControllerUpdateError(snapshot.Name, err.Error())
}
@@ -1055,7 +1072,7 @@ func (ctrl *csiSnapshotController) removeSnapshotFinalizer(snapshot *crdv1.Volum
snapshotClone := snapshot.DeepCopy()
snapshotClone.ObjectMeta.Finalizers = slice.RemoveString(snapshotClone.ObjectMeta.Finalizers, VolumeSnapshotFinalizer, nil)
_, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone)
_, err := ctrl.clientset.SnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone)
if err != nil {
return newControllerUpdateError(snapshot.Name, err.Error())
}
@@ -1068,3 +1085,113 @@ func (ctrl *csiSnapshotController) removeSnapshotFinalizer(snapshot *crdv1.Volum
klog.V(5).Infof("Removed protection finalizer from volume snapshot %s", snapshotKey(snapshot))
return nil
}
// ensureSnapshotSourceFinalizer checks if a Finalizer needs to be added for the snapshot source;
// if true, adds a Finalizer for VolumeSnapshot Source PVC
func (ctrl *csiSnapshotController) ensureSnapshotSourceFinalizer(snapshot *crdv1.VolumeSnapshot) error {
// Get snapshot source which is a PVC
pvc, err := ctrl.getClaimFromVolumeSnapshot(snapshot)
if err != nil {
klog.Infof("cannot get claim from snapshot [%s]: [%v] Claim may be deleted already.", snapshot.Name, err)
return nil
}
// If PVC is not being deleted and PVCFinalizer is not added yet, the PVCFinalizer should be added.
if pvc.ObjectMeta.DeletionTimestamp == nil && !slice.ContainsString(pvc.ObjectMeta.Finalizers, PVCFinalizer, nil) {
// Add the finalizer
pvcClone := pvc.DeepCopy()
pvcClone.ObjectMeta.Finalizers = append(pvcClone.ObjectMeta.Finalizers, PVCFinalizer)
_, err = ctrl.client.CoreV1().PersistentVolumeClaims(pvcClone.Namespace).Update(pvcClone)
if err != nil {
klog.Errorf("cannot add finalizer on claim [%s] for snapshot [%s]: [%v]", pvc.Name, snapshot.Name, err)
return newControllerUpdateError(pvcClone.Name, err.Error())
}
klog.Infof("Added protection finalizer to persistent volume claim %s", pvc.Name)
}
return nil
}
// removeSnapshotSourceFinalizer removes a Finalizer for VolumeSnapshot Source PVC.
func (ctrl *csiSnapshotController) removeSnapshotSourceFinalizer(snapshot *crdv1.VolumeSnapshot) error {
// Get snapshot source which is a PVC
pvc, err := ctrl.getClaimFromVolumeSnapshot(snapshot)
if err != nil {
klog.Infof("cannot get claim from snapshot [%s]: [%v] Claim may be deleted already. No need to remove finalizer on the claim.", snapshot.Name, err)
return nil
}
pvcClone := pvc.DeepCopy()
pvcClone.ObjectMeta.Finalizers = slice.RemoveString(pvcClone.ObjectMeta.Finalizers, PVCFinalizer, nil)
_, err = ctrl.client.CoreV1().PersistentVolumeClaims(pvcClone.Namespace).Update(pvcClone)
if err != nil {
return newControllerUpdateError(pvcClone.Name, err.Error())
}
klog.V(5).Infof("Removed protection finalizer from persistent volume claim %s", pvc.Name)
return nil
}
// isSnapshotSourceBeingUsed checks if a PVC is being used as a source to create a snapshot
func (ctrl *csiSnapshotController) isSnapshotSourceBeingUsed(snapshot *crdv1.VolumeSnapshot) bool {
klog.V(5).Infof("isSnapshotSourceBeingUsed[%s]: started", snapshotKey(snapshot))
// Get snapshot source which is a PVC
pvc, err := ctrl.getClaimFromVolumeSnapshot(snapshot)
if err != nil {
klog.Infof("isSnapshotSourceBeingUsed: cannot to get claim from snapshot: %v", err)
return false
}
// Going through snapshots in the cache (snapshotLister). If a snapshot's PVC source
// is the same as the input snapshot's PVC source and snapshot's ReadyToUse status
// is false, the snapshot is still being created from the PVC and the PVC is in-use.
snapshots, err := ctrl.snapshotLister.VolumeSnapshots(snapshot.Namespace).List(labels.Everything())
if err != nil {
return false
}
for _, snap := range snapshots {
// Skip static bound snapshot without a PVC source
if snap.Spec.Source == nil {
klog.V(4).Infof("Skipping static bound snapshot %s when checking PVC %s/%s", snap.Name, pvc.Namespace, pvc.Name)
continue
}
if pvc.Name == snap.Spec.Source.Name && snap.Status.ReadyToUse == false {
klog.V(2).Infof("Keeping PVC %s/%s, it is used by snapshot %s/%s", pvc.Namespace, pvc.Name, snap.Namespace, snap.Name)
return true
}
}
klog.V(5).Infof("isSnapshotSourceBeingUsed: no snapshot is being created from PVC %s/%s", pvc.Namespace, pvc.Name)
return false
}
// checkandRemoveSnapshotSourceFinalizer checks if the snapshot source finalizer should be removed
// and removed it if needed.
func (ctrl *csiSnapshotController) checkandRemoveSnapshotSourceFinalizer(snapshot *crdv1.VolumeSnapshot) error {
// Get snapshot source which is a PVC
pvc, err := ctrl.getClaimFromVolumeSnapshot(snapshot)
if err != nil {
klog.Infof("cannot get claim from snapshot [%s]: [%v] Claim may be deleted already. No need to remove finalizer on the claim.", snapshot.Name, err)
return nil
}
klog.V(5).Infof("checkandRemoveSnapshotSourceFinalizer for snapshot [%s]: snapshot status [%#v]", snapshot.Name, snapshot.Status)
// Check if there is a Finalizer on PVC to be removed
if slice.ContainsString(pvc.ObjectMeta.Finalizers, PVCFinalizer, nil) {
// There is a Finalizer on PVC. Check if PVC is used
// and remove finalizer if it's not used.
isUsed := ctrl.isSnapshotSourceBeingUsed(snapshot)
if !isUsed {
klog.Infof("checkandRemoveSnapshotSourceFinalizer[%s]: Remove Finalizer for PVC %s as it is not used by snapshots in creation", snapshot.Name, pvc.Name)
err = ctrl.removeSnapshotSourceFinalizer(snapshot)
if err != nil {
klog.Errorf("checkandRemoveSnapshotSourceFinalizer [%s]: removeSnapshotSourceFinalizer failed to remove finalizer %v", snapshot.Name, err)
return err
}
}
}
return nil
}

View File

@@ -27,10 +27,11 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var timeNow = time.Now().UnixNano()
var timeNow = time.Now()
var timeNowStamp = timeNow.UnixNano()
var metaTimeNowUnix = &metav1.Time{
Time: time.Unix(0, timeNow),
Time: timeNow,
}
var defaultSize int64 = 1000
@@ -68,7 +69,7 @@ func TestCreateSnapshotSync(t *testing.T) {
{
name: "6-1 - successful create snapshot with snapshot class gold",
initialContents: nocontents,
expectedContents: newContentArray("snapcontent-snapuid6-1", classGold, "sid6-1", "pv-uid6-1", "volume6-1", "snapuid6-1", "snap6-1", &deletePolicy, &defaultSize, &timeNow, false),
expectedContents: newContentArray("snapcontent-snapuid6-1", classGold, "sid6-1", "pv-uid6-1", "volume6-1", "snapuid6-1", "snap6-1", &deletePolicy, &defaultSize, &timeNowStamp, false),
initialSnapshots: newSnapshotArray("snap6-1", classGold, "", "snapuid6-1", "claim6-1", false, nil, nil, nil),
expectedSnapshots: newSnapshotArray("snap6-1", classGold, "snapcontent-snapuid6-1", "snapuid6-1", "claim6-1", false, nil, metaTimeNowUnix, getSize(defaultSize)),
initialClaims: newClaimArray("claim6-1", "pvc-uid6-1", "1Gi", "volume6-1", v1.ClaimBound, &classEmpty),
@@ -82,7 +83,7 @@ func TestCreateSnapshotSync(t *testing.T) {
driverName: mockDriverName,
size: defaultSize,
snapshotId: "sid6-1",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},
@@ -92,7 +93,7 @@ func TestCreateSnapshotSync(t *testing.T) {
{
name: "6-2 - successful create snapshot with snapshot class silver",
initialContents: nocontents,
expectedContents: newContentArray("snapcontent-snapuid6-2", classSilver, "sid6-2", "pv-uid6-2", "volume6-2", "snapuid6-2", "snap6-2", &deletePolicy, &defaultSize, &timeNow, false),
expectedContents: newContentArray("snapcontent-snapuid6-2", classSilver, "sid6-2", "pv-uid6-2", "volume6-2", "snapuid6-2", "snap6-2", &deletePolicy, &defaultSize, &timeNowStamp, false),
initialSnapshots: newSnapshotArray("snap6-2", classSilver, "", "snapuid6-2", "claim6-2", false, nil, nil, nil),
expectedSnapshots: newSnapshotArray("snap6-2", classSilver, "snapcontent-snapuid6-2", "snapuid6-2", "claim6-2", false, nil, metaTimeNowUnix, getSize(defaultSize)),
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
@@ -106,7 +107,7 @@ func TestCreateSnapshotSync(t *testing.T) {
driverName: mockDriverName,
size: defaultSize,
snapshotId: "sid6-2",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},
@@ -116,7 +117,7 @@ func TestCreateSnapshotSync(t *testing.T) {
{
name: "6-3 - successful create snapshot with snapshot class valid-secret-class",
initialContents: nocontents,
expectedContents: newContentArray("snapcontent-snapuid6-3", validSecretClass, "sid6-3", "pv-uid6-3", "volume6-3", "snapuid6-3", "snap6-3", &deletePolicy, &defaultSize, &timeNow, false),
expectedContents: newContentArray("snapcontent-snapuid6-3", validSecretClass, "sid6-3", "pv-uid6-3", "volume6-3", "snapuid6-3", "snap6-3", &deletePolicy, &defaultSize, &timeNowStamp, false),
initialSnapshots: newSnapshotArray("snap6-3", validSecretClass, "", "snapuid6-3", "claim6-3", false, nil, nil, nil),
expectedSnapshots: newSnapshotArray("snap6-3", validSecretClass, "snapcontent-snapuid6-3", "snapuid6-3", "claim6-3", false, nil, metaTimeNowUnix, getSize(defaultSize)),
initialClaims: newClaimArray("claim6-3", "pvc-uid6-3", "1Gi", "volume6-3", v1.ClaimBound, &classEmpty),
@@ -132,7 +133,7 @@ func TestCreateSnapshotSync(t *testing.T) {
driverName: mockDriverName,
size: defaultSize,
snapshotId: "sid6-3",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},
@@ -142,7 +143,7 @@ func TestCreateSnapshotSync(t *testing.T) {
{
name: "6-4 - successful create snapshot with snapshot class empty-secret-class",
initialContents: nocontents,
expectedContents: newContentArray("snapcontent-snapuid6-4", emptySecretClass, "sid6-4", "pv-uid6-4", "volume6-4", "snapuid6-4", "snap6-4", &deletePolicy, &defaultSize, &timeNow, false),
expectedContents: newContentArray("snapcontent-snapuid6-4", emptySecretClass, "sid6-4", "pv-uid6-4", "volume6-4", "snapuid6-4", "snap6-4", &deletePolicy, &defaultSize, &timeNowStamp, false),
initialSnapshots: newSnapshotArray("snap6-4", emptySecretClass, "", "snapuid6-4", "claim6-4", false, nil, nil, nil),
expectedSnapshots: newSnapshotArray("snap6-4", emptySecretClass, "snapcontent-snapuid6-4", "snapuid6-4", "claim6-4", false, nil, metaTimeNowUnix, getSize(defaultSize)),
initialClaims: newClaimArray("claim6-4", "pvc-uid6-4", "1Gi", "volume6-4", v1.ClaimBound, &classEmpty),
@@ -158,7 +159,7 @@ func TestCreateSnapshotSync(t *testing.T) {
driverName: mockDriverName,
size: defaultSize,
snapshotId: "sid6-4",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},
@@ -168,7 +169,7 @@ func TestCreateSnapshotSync(t *testing.T) {
{
name: "6-5 - successful create snapshot with status uploading",
initialContents: nocontents,
expectedContents: newContentArray("snapcontent-snapuid6-5", classGold, "sid6-5", "pv-uid6-5", "volume6-5", "snapuid6-5", "snap6-5", &deletePolicy, &defaultSize, &timeNow, false),
expectedContents: newContentArray("snapcontent-snapuid6-5", classGold, "sid6-5", "pv-uid6-5", "volume6-5", "snapuid6-5", "snap6-5", &deletePolicy, &defaultSize, &timeNowStamp, false),
initialSnapshots: newSnapshotArray("snap6-5", classGold, "", "snapuid6-5", "claim6-5", false, nil, nil, nil),
expectedSnapshots: newSnapshotArray("snap6-5", classGold, "snapcontent-snapuid6-5", "snapuid6-5", "claim6-5", false, nil, metaTimeNowUnix, getSize(defaultSize)),
initialClaims: newClaimArray("claim6-5", "pvc-uid6-5", "1Gi", "volume6-5", v1.ClaimBound, &classEmpty),
@@ -182,7 +183,7 @@ func TestCreateSnapshotSync(t *testing.T) {
driverName: mockDriverName,
size: defaultSize,
snapshotId: "sid6-5",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},
@@ -192,7 +193,7 @@ func TestCreateSnapshotSync(t *testing.T) {
{
name: "6-6 - successful create snapshot with status error uploading",
initialContents: nocontents,
expectedContents: newContentArray("snapcontent-snapuid6-6", classGold, "sid6-6", "pv-uid6-6", "volume6-6", "snapuid6-6", "snap6-6", &deletePolicy, &defaultSize, &timeNow, false),
expectedContents: newContentArray("snapcontent-snapuid6-6", classGold, "sid6-6", "pv-uid6-6", "volume6-6", "snapuid6-6", "snap6-6", &deletePolicy, &defaultSize, &timeNowStamp, false),
initialSnapshots: newSnapshotArray("snap6-6", classGold, "", "snapuid6-6", "claim6-6", false, nil, nil, nil),
expectedSnapshots: newSnapshotArray("snap6-6", classGold, "snapcontent-snapuid6-6", "snapuid6-6", "claim6-6", false, nil, metaTimeNowUnix, getSize(defaultSize)),
initialClaims: newClaimArray("claim6-6", "pvc-uid6-6", "1Gi", "volume6-6", v1.ClaimBound, &classEmpty),
@@ -206,7 +207,7 @@ func TestCreateSnapshotSync(t *testing.T) {
driverName: mockDriverName,
size: defaultSize,
snapshotId: "sid6-6",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},
@@ -321,7 +322,7 @@ func TestCreateSnapshotSync(t *testing.T) {
driverName: mockDriverName,
size: defaultSize,
snapshotId: "sid7-8",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},
@@ -352,7 +353,7 @@ func TestCreateSnapshotSync(t *testing.T) {
driverName: mockDriverName,
size: defaultSize,
snapshotId: "sid7-9",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},

View File

@@ -0,0 +1,67 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"testing"
"k8s.io/api/core/v1"
)
// Test single call to ensureSnapshotSourceFinalizer and checkandRemoveSnapshotSourceFinalizer,
// expecting PVCFinalizer to be added or removed
func TestPVCFinalizer(t *testing.T) {
tests := []controllerTest{
{
name: "1-1 - successful add PVC finalizer",
initialSnapshots: newSnapshotArray("snap6-2", classSilver, "", "snapuid6-2", "claim6-2", false, nil, nil, nil),
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
test: testAddPVCFinalizer,
expectSuccess: true,
},
{
name: "1-2 - won't add PVC finalizer; already added",
initialSnapshots: newSnapshotArray("snap6-2", classSilver, "", "snapuid6-2", "claim6-2", false, nil, nil, nil),
initialClaims: newClaimArrayFinalizer("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
test: testAddPVCFinalizer,
expectSuccess: false,
},
{
name: "1-3 - successful remove PVC finalizer",
initialSnapshots: newSnapshotArray("snap6-2", classSilver, "", "snapuid6-2", "claim6-2", false, nil, nil, nil),
initialClaims: newClaimArrayFinalizer("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
test: testRemovePVCFinalizer,
expectSuccess: true,
},
{
name: "1-4 - won't remove PVC finalizer; already removed",
initialSnapshots: newSnapshotArray("snap6-2", classSilver, "", "snapuid6-2", "claim6-2", false, nil, nil, nil),
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
test: testRemovePVCFinalizer,
expectSuccess: false,
},
{
name: "1-5 - won't remove PVC finalizer; PVC in-use",
initialSnapshots: newSnapshotArray("snap6-2", classSilver, "", "snapuid6-2", "claim6-2", false, nil, nil, nil),
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
test: testRemovePVCFinalizer,
expectSuccess: false,
},
}
runPVCFinalizerTests(t, tests, snapshotClasses)
}

View File

@@ -81,7 +81,7 @@ func TestSync(t *testing.T) {
// information to return
driverName: mockDriverName,
snapshotId: "sid2-3",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: false,
},
},
@@ -116,7 +116,7 @@ func TestSync(t *testing.T) {
// information to return
driverName: mockDriverName,
snapshotId: "sid2-5",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},
@@ -125,8 +125,8 @@ func TestSync(t *testing.T) {
},
{
name: "2-6 - snapshot bound to prebound content correctly, status ready false -> true, ref.UID '' -> 'snapuid2-6'",
initialContents: newContentArray("content2-6", validSecretClass, "sid2-6", noVolume, noVolume, noBoundUID, "snap2-6", &deletePolicy, nil, &timeNow, false),
expectedContents: newContentArray("content2-6", validSecretClass, "sid2-6", noVolume, noVolume, "snapuid2-6", "snap2-6", &deletePolicy, nil, &timeNow, false),
initialContents: newContentArray("content2-6", validSecretClass, "sid2-6", noVolume, noVolume, noBoundUID, "snap2-6", &deletePolicy, nil, &timeNowStamp, false),
expectedContents: newContentArray("content2-6", validSecretClass, "sid2-6", noVolume, noVolume, "snapuid2-6", "snap2-6", &deletePolicy, nil, &timeNowStamp, false),
initialSnapshots: newSnapshotArray("snap2-6", validSecretClass, "content2-6", "snapuid2-6", noClaim, false, nil, metaTimeNow, nil),
expectedSnapshots: newSnapshotArray("snap2-6", validSecretClass, "content2-6", "snapuid2-6", noClaim, true, nil, metaTimeNow, nil),
expectedListCalls: []listCall{
@@ -181,7 +181,7 @@ func TestSync(t *testing.T) {
driverName: mockDriverName,
size: defaultSize,
snapshotId: "sid2-8",
timestamp: timeNow,
creationTime: timeNow,
readyToUse: true,
},
},

View File

@@ -75,6 +75,9 @@ var snapshotterSecretParams = deprecatedSecretParamsMap{
secretNamespaceKey: prefixedSnapshotterSecretNamespaceKey,
}
// Name of finalizer on PVCs that have been used as a source to create VolumeSnapshots
const PVCFinalizer = "snapshot.storage.kubernetes.io/pvc-protection"
func snapshotKey(vs *crdv1.VolumeSnapshot) string {
return fmt.Sprintf("%s/%s", vs.Namespace, vs.Name)
}

View File

@@ -19,10 +19,10 @@ package snapshotter
import (
"context"
"fmt"
"time"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/timestamp"
csirpc "github.com/kubernetes-csi/csi-lib-utils/rpc"
"google.golang.org/grpc"
@@ -34,13 +34,13 @@ import (
// Snapshotter implements CreateSnapshot/DeleteSnapshot operations against a remote CSI driver.
type Snapshotter interface {
// CreateSnapshot creates a snapshot for a volume
CreateSnapshot(ctx context.Context, snapshotName string, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (driverName string, snapshotId string, timestamp int64, size int64, readyToUse bool, err error)
CreateSnapshot(ctx context.Context, snapshotName string, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (driverName string, snapshotId string, timestamp time.Time, size int64, readyToUse bool, err error)
// DeleteSnapshot deletes a snapshot from a volume
DeleteSnapshot(ctx context.Context, snapshotID string, snapshotterCredentials map[string]string) (err error)
// GetSnapshotStatus returns if a snapshot is ready to use, creation time, and restore size.
GetSnapshotStatus(ctx context.Context, snapshotID string) (bool, int64, int64, error)
GetSnapshotStatus(ctx context.Context, snapshotID string) (bool, time.Time, int64, error)
}
type snapshot struct {
@@ -53,17 +53,17 @@ func NewSnapshotter(conn *grpc.ClientConn) Snapshotter {
}
}
func (s *snapshot) CreateSnapshot(ctx context.Context, snapshotName string, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (string, string, int64, int64, bool, error) {
func (s *snapshot) CreateSnapshot(ctx context.Context, snapshotName string, volume *v1.PersistentVolume, parameters map[string]string, snapshotterCredentials map[string]string) (string, string, time.Time, int64, bool, error) {
klog.V(5).Infof("CSI CreateSnapshot: %s", snapshotName)
if volume.Spec.CSI == nil {
return "", "", 0, 0, false, fmt.Errorf("CSIPersistentVolumeSource not defined in spec")
return "", "", time.Time{}, 0, false, fmt.Errorf("CSIPersistentVolumeSource not defined in spec")
}
client := csi.NewControllerClient(s.conn)
driverName, err := csirpc.GetDriverName(ctx, s.conn)
if err != nil {
return "", "", 0, 0, false, err
return "", "", time.Time{}, 0, false, err
}
req := csi.CreateSnapshotRequest{
@@ -75,13 +75,13 @@ func (s *snapshot) CreateSnapshot(ctx context.Context, snapshotName string, volu
rsp, err := client.CreateSnapshot(ctx, &req)
if err != nil {
return "", "", 0, 0, false, err
return "", "", time.Time{}, 0, false, err
}
klog.V(5).Infof("CSI CreateSnapshot: %s driver name [%s] snapshot ID [%s] time stamp [%d] size [%d] readyToUse [%v]", snapshotName, driverName, rsp.Snapshot.SnapshotId, rsp.Snapshot.CreationTime, rsp.Snapshot.SizeBytes, rsp.Snapshot.ReadyToUse)
creationTime, err := timestampToUnixTime(rsp.Snapshot.CreationTime)
creationTime, err := ptypes.Timestamp(rsp.Snapshot.CreationTime)
if err != nil {
return "", "", 0, 0, false, err
return "", "", time.Time{}, 0, false, err
}
return driverName, rsp.Snapshot.SnapshotId, creationTime, rsp.Snapshot.SizeBytes, rsp.Snapshot.ReadyToUse, nil
}
@@ -101,7 +101,7 @@ func (s *snapshot) DeleteSnapshot(ctx context.Context, snapshotID string, snapsh
return nil
}
func (s *snapshot) GetSnapshotStatus(ctx context.Context, snapshotID string) (bool, int64, int64, error) {
func (s *snapshot) GetSnapshotStatus(ctx context.Context, snapshotID string) (bool, time.Time, int64, error) {
client := csi.NewControllerClient(s.conn)
req := csi.ListSnapshotsRequest{
@@ -110,26 +110,16 @@ func (s *snapshot) GetSnapshotStatus(ctx context.Context, snapshotID string) (bo
rsp, err := client.ListSnapshots(ctx, &req)
if err != nil {
return false, 0, 0, err
return false, time.Time{}, 0, err
}
if rsp.Entries == nil || len(rsp.Entries) == 0 {
return false, 0, 0, fmt.Errorf("can not find snapshot for snapshotID %s", snapshotID)
return false, time.Time{}, 0, fmt.Errorf("can not find snapshot for snapshotID %s", snapshotID)
}
creationTime, err := timestampToUnixTime(rsp.Entries[0].Snapshot.CreationTime)
creationTime, err := ptypes.Timestamp(rsp.Entries[0].Snapshot.CreationTime)
if err != nil {
return false, 0, 0, err
return false, time.Time{}, 0, err
}
return rsp.Entries[0].Snapshot.ReadyToUse, creationTime, rsp.Entries[0].Snapshot.SizeBytes, nil
}
func timestampToUnixTime(t *timestamp.Timestamp) (int64, error) {
time, err := ptypes.Timestamp(t)
if err != nil {
return -1, err
}
// TODO: clean this up, we probably don't need this translation layer
// and can just use time.Time
return time.UnixNano(), nil
}

View File

@@ -21,6 +21,7 @@ import (
"fmt"
"reflect"
"testing"
"time"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/mock/gomock"
@@ -118,7 +119,7 @@ func TestCreateSnapshot(t *testing.T) {
type snapshotResult struct {
driverName string
snapshotId string
timestamp int64
timestamp time.Time
size int64
readyToUse bool
}
@@ -127,7 +128,7 @@ func TestCreateSnapshot(t *testing.T) {
size: 1000,
driverName: driverName,
snapshotId: defaultID,
timestamp: createTime.UnixNano(),
timestamp: createTime,
readyToUse: true,
}
@@ -376,7 +377,7 @@ func TestGetSnapshotStatus(t *testing.T) {
injectError codes.Code
expectError bool
expectReady bool
expectCreateAt int64
expectCreateAt time.Time
expectSize int64
}{
{
@@ -386,7 +387,7 @@ func TestGetSnapshotStatus(t *testing.T) {
output: defaultResponse,
expectError: false,
expectReady: true,
expectCreateAt: createTime.UnixNano(),
expectCreateAt: createTime,
expectSize: size,
},
{