Skip to content

Commit cf2335f

Browse files
authored
Merge branch 'master' into testgetdrivename
2 parents 2ca0790 + f3c041b commit cf2335f

File tree

224 files changed

+20557
-1412
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

224 files changed

+20557
-1412
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ script:
1414
- go test $(go list ./... | grep -v vendor)
1515
after_success:
1616
- if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then
17-
sudo ./hack/build-container.sh;
17+
make container;
1818
docker login -u "${DOCKER_USERNAME}" -p "${DOCKER_PASSWORD}" quay.io;
1919
docker push quay.io/k8scsi/csi-provisioner:canary;
2020
fi

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414

1515
IMAGE_NAME = quay.io/k8scsi/csi-provisioner
16-
IMAGE_VERSION = v0.2.0
16+
IMAGE_VERSION = canary
1717

1818
ifdef V
1919
TESTARGS = -v -args -alsologtostderr -v 5
@@ -25,7 +25,7 @@ all: csi-provisioner
2525

2626
csi-provisioner:
2727
mkdir -p bin
28-
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o ./bin/csi-provisioner ./cmd/csi-provisioner
28+
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o ./bin/csi-provisioner ./cmd/csi-provisioner
2929

3030
clean:
3131
rm -rf bin deploy/docker/csi-provisioner

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
[![Build Status](https://travis-ci.org/kubernetes-csi/external-provisioner.svg?branch=master)](https://travis-ci.org/kubernetes-csi/external-provisioner)
12
# Kubernetes external provisioner that works with CSI volumes.
23

34
This is an example external provisioner for Kubernetes which provisions using CSI Volume drivers.. It's under heavy development, so at this time README.md is notes for the developers coding. Once complete this will change to something user friendly.

cmd/csi-provisioner/csi-provisioner.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import (
2828
ctrl "github.com/kubernetes-csi/external-provisioner/pkg/controller"
2929
"github.com/kubernetes-incubator/external-storage/lib/controller"
3030

31+
"google.golang.org/grpc"
32+
3133
"k8s.io/apimachinery/pkg/util/wait"
3234
"k8s.io/client-go/kubernetes"
3335
"k8s.io/client-go/rest"
@@ -38,7 +40,7 @@ var (
3840
provisioner = flag.String("provisioner", "", "Name of the provisioner. The provisioner will only provision volumes for claims that request a StorageClass with a provisioner field set equal to this name.")
3941
master = flag.String("master", "", "Master URL to build a client config from. Either this or kubeconfig needs to be set if the provisioner is being run out of cluster.")
4042
kubeconfig = flag.String("kubeconfig", "", "Absolute path to the kubeconfig file. Either this or master needs to be set if the provisioner is being run out of cluster.")
41-
csiEndpoint = flag.String("csi-address", "", "The gRPC endpoint for Target CSI Volume")
43+
csiEndpoint = flag.String("csi-address", "/run/csi/socket", "The gRPC endpoint for Target CSI Volume")
4244
connectionTimeout = flag.Duration("connection-timeout", 10*time.Second, "Timeout for waiting for CSI driver socket.")
4345
volumeNamePrefix = flag.String("volume-name-prefix", "kubernetes-dynamic-pv", "Prefix to apply to the name of a created volume")
4446
volumeNameUUIDLength = flag.Int("volume-name-uuid-length", 16, "Length in characters for the generated uuid of a created volume")
@@ -87,9 +89,21 @@ func init() {
8789
timeStamp := time.Now().UnixNano() / int64(time.Millisecond)
8890
identity := strconv.FormatInt(timeStamp, 10) + "-" + strconv.Itoa(rand.Intn(10000)) + "-" + *provisioner
8991

92+
// Provisioner will stay in Init until driver opens csi socket, once it's done
93+
// controller will exit this loop and proceed normally.
94+
socketDown := true
95+
grpcClient := &grpc.ClientConn{}
96+
for socketDown {
97+
grpcClient, err = ctrl.Connect(*csiEndpoint, *connectionTimeout)
98+
if err == nil {
99+
socketDown = false
100+
continue
101+
}
102+
time.Sleep(10 * time.Second)
103+
}
90104
// Create the provisioner: it implements the Provisioner interface expected by
91105
// the controller
92-
csiProvisioner := ctrl.NewCSIProvisioner(clientset, *csiEndpoint, *connectionTimeout, identity, *volumeNamePrefix, *volumeNameUUIDLength)
106+
csiProvisioner := ctrl.NewCSIProvisioner(clientset, *csiEndpoint, *connectionTimeout, identity, *volumeNamePrefix, *volumeNameUUIDLength, grpcClient)
93107
provisionController = controller.NewProvisionController(
94108
clientset,
95109
*provisioner,

hack/build-container.sh

Lines changed: 0 additions & 13 deletions
This file was deleted.

main.go

Lines changed: 0 additions & 7 deletions
This file was deleted.

pkg/controller/controller.go

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ const (
4444
secretNamespaceKey = "csiProvisionerSecretNamespace"
4545
)
4646

47+
// CSIProvisioner struct
4748
type csiProvisioner struct {
4849
client kubernetes.Interface
4950
csiClient csi.ControllerClient
50-
driverName string
51+
grpcClient *grpc.ClientConn
5152
timeout time.Duration
5253
identity string
5354
volumeNamePrefix string
@@ -80,7 +81,7 @@ func logGRPC(ctx context.Context, method string, req, reply interface{}, cc *grp
8081
return err
8182
}
8283

83-
func connect(address string, timeout time.Duration) (*grpc.ClientConn, error) {
84+
func Connect(address string, timeout time.Duration) (*grpc.ClientConn, error) {
8485
glog.V(2).Infof("Connecting to %s", address)
8586
dialOptions := []grpc.DialOption{
8687
grpc.WithInsecure(),
@@ -102,7 +103,7 @@ func connect(address string, timeout time.Duration) (*grpc.ClientConn, error) {
102103
for {
103104
if !conn.WaitForStateChange(ctx, conn.GetState()) {
104105
glog.V(4).Infof("Connection timed out")
105-
return conn, nil // return nil, subsequent GetPluginInfo will show the real connection error
106+
return conn, fmt.Errorf("Connection timed out")
106107
}
107108
if conn.GetState() == connectivity.Ready {
108109
glog.V(3).Infof("Connected")
@@ -185,34 +186,19 @@ func supportsControllerCreateVolume(conn *grpc.ClientConn, timeout time.Duration
185186
return false, nil
186187
}
187188

188-
func NewCSIProvisioner(client kubernetes.Interface, csiEndpoint string, connectionTimeout time.Duration, identity string, volumeNamePrefix string, volumeNameUUIDLength int) controller.Provisioner {
189-
grpcClient, err := connect(csiEndpoint, connectionTimeout)
190-
if err != nil || grpcClient == nil {
191-
glog.Fatalf("failed to connect to csi endpoint :%v", err)
192-
}
193-
ok, err := supportsPluginControllerService(grpcClient, connectionTimeout)
194-
if err != nil {
195-
glog.Fatalf("failed to get support info :%v", err)
196-
}
197-
if !ok {
198-
glog.Fatalf("no plugin controller service support detected")
199-
}
200-
ok, err = supportsControllerCreateVolume(grpcClient, connectionTimeout)
201-
if err != nil {
202-
glog.Fatalf("failed to get support info :%v", err)
203-
}
204-
if !ok {
205-
glog.Fatalf("no create/delete volume support detected")
206-
}
207-
driver, err := getDriverName(grpcClient, connectionTimeout)
208-
if err != nil {
209-
glog.Fatalf("failed to get driver info :%v", err)
210-
}
189+
// NewCSIProvisioner creates new CSI provisioner
190+
func NewCSIProvisioner(client kubernetes.Interface,
191+
csiEndpoint string,
192+
connectionTimeout time.Duration,
193+
identity string,
194+
volumeNamePrefix string,
195+
volumeNameUUIDLength int,
196+
grpcClient *grpc.ClientConn) controller.Provisioner {
211197

212198
csiClient := csi.NewControllerClient(grpcClient)
213199
provisioner := &csiProvisioner{
214200
client: client,
215-
driverName: driver,
201+
grpcClient: grpcClient,
216202
csiClient: csiClient,
217203
timeout: connectionTimeout,
218204
identity: identity,
@@ -222,10 +208,45 @@ func NewCSIProvisioner(client kubernetes.Interface, csiEndpoint string, connecti
222208
return provisioner
223209
}
224210

211+
// This function get called before any attepmt to communicate with the driver.
212+
// Before initiating Create/Delete API calls provisioner checks if Capabilities:
213+
// PluginControllerService, ControllerCreateVolume sre supported and gets the driver name.
214+
func checkDriverState(grpcClient *grpc.ClientConn, timeout time.Duration) (string, error) {
215+
ok, err := supportsPluginControllerService(grpcClient, timeout)
216+
if err != nil {
217+
glog.Errorf("failed to get support info :%v", err)
218+
return "", err
219+
}
220+
if !ok {
221+
glog.Errorf("no plugin controller service support detected")
222+
return "", fmt.Errorf("no plugin controller service support detected")
223+
}
224+
ok, err = supportsControllerCreateVolume(grpcClient, timeout)
225+
if err != nil {
226+
glog.Errorf("failed to get support info :%v", err)
227+
return "", err
228+
}
229+
if !ok {
230+
glog.Error("no create/delete volume support detected")
231+
return "", fmt.Errorf("no create/delete volume support detected")
232+
}
233+
driverName, err := getDriverName(grpcClient, timeout)
234+
if err != nil {
235+
glog.Errorf("failed to get driver info :%v", err)
236+
return "", err
237+
}
238+
return driverName, nil
239+
}
240+
225241
func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) {
226242
if options.PVC.Spec.Selector != nil {
227243
return nil, fmt.Errorf("claim Selector is not supported")
228244
}
245+
246+
driverName, err := checkDriverState(p.grpcClient, p.timeout)
247+
if err != nil {
248+
return nil, err
249+
}
229250
// create random share name
230251
share := fmt.Sprintf("%s-%s", p.volumeNamePrefix, strings.Replace(string(uuid.NewUUID()), "-", "", -1)[0:p.volumeNameUUIDLength])
231252
capacity := options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
@@ -249,7 +270,11 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
249270
}
250271
secret := v1.SecretReference{}
251272
if options.Parameters != nil {
252-
req.ControllerCreateSecrets = getCredentialsFromParameters(p.client, options.Parameters)
273+
credentials, err := getCredentialsFromParameters(p.client, options.Parameters)
274+
if err != nil {
275+
return nil, err
276+
}
277+
req.ControllerCreateSecrets = credentials
253278
secret.Name, secret.Namespace, _ = getSecretAndNamespaceFromParameters(options.Parameters)
254279
}
255280
ctx, cancel := context.WithTimeout(context.Background(), p.timeout)
@@ -279,7 +304,7 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
279304
// TODO wait for CSI VolumeSource API
280305
PersistentVolumeSource: v1.PersistentVolumeSource{
281306
CSI: &v1.CSIPersistentVolumeSource{
282-
Driver: p.driverName,
307+
Driver: driverName,
283308
VolumeHandle: p.volumeIdToHandle(rep.Volume.Id),
284309
VolumeAttributes: volumeAttributes,
285310
},
@@ -300,21 +325,30 @@ func (p *csiProvisioner) Delete(volume *v1.PersistentVolume) error {
300325
}
301326
volumeId := p.volumeHandleToId(volume.Spec.CSI.VolumeHandle)
302327

328+
_, err := checkDriverState(p.grpcClient, p.timeout)
329+
if err != nil {
330+
return err
331+
}
332+
303333
req := csi.DeleteVolumeRequest{
304334
VolumeId: volumeId,
305335
}
306336
// get secrets if StorageClass specifies it
307337
storageClassName := volume.Spec.StorageClassName
308338
if len(storageClassName) != 0 {
309339
if storageClass, err := p.client.StorageV1().StorageClasses().Get(storageClassName, metav1.GetOptions{}); err == nil {
310-
req.ControllerDeleteSecrets = getCredentialsFromParameters(p.client, storageClass.Parameters)
340+
credentials, err := getCredentialsFromParameters(p.client, storageClass.Parameters)
341+
if err != nil {
342+
return err
343+
}
344+
req.ControllerDeleteSecrets = credentials
311345
}
312346

313347
}
314348
ctx, cancel := context.WithTimeout(context.Background(), p.timeout)
315349
defer cancel()
316350

317-
_, err := p.csiClient.DeleteVolume(ctx, &req)
351+
_, err = p.csiClient.DeleteVolume(ctx, &req)
318352

319353
return err
320354
}
@@ -330,11 +364,11 @@ func getSecretAndNamespaceFromParameters(parameters map[string]string) (string,
330364
return "", "", false
331365
}
332366

333-
func getCredentialsFromParameters(k8s kubernetes.Interface, parameters map[string]string) map[string]string {
367+
func getCredentialsFromParameters(k8s kubernetes.Interface, parameters map[string]string) (map[string]string, error) {
334368
if secretName, namespace, found := getSecretAndNamespaceFromParameters(parameters); found {
335369
return getCredentialsFromSecret(k8s, secretName, namespace)
336370
}
337-
return map[string]string{}
371+
return map[string]string{}, nil
338372
}
339373

340374
//TODO use a unique volume handle from and to Id
@@ -346,19 +380,18 @@ func (p *csiProvisioner) volumeHandleToId(handle string) string {
346380
return handle
347381
}
348382

349-
func getCredentialsFromSecret(k8s kubernetes.Interface, secretName, nameSpace string) map[string]string {
383+
func getCredentialsFromSecret(k8s kubernetes.Interface, secretName, nameSpace string) (map[string]string, error) {
350384
credentials := map[string]string{}
351385
if len(secretName) == 0 {
352-
return credentials
386+
return credentials, nil
353387
}
354388
secret, err := k8s.CoreV1().Secrets(nameSpace).Get(secretName, metav1.GetOptions{})
355389
if err != nil {
356-
glog.Warningf("failed to find the secret %s in the namespace %s with error: %v\n", secretName, nameSpace, err)
357-
return credentials
390+
return credentials, fmt.Errorf("failed to find the secret %s in the namespace %s with error: %v\n", secretName, nameSpace, err)
358391
}
359392
for key, value := range secret.Data {
360393
credentials[key] = string(value)
361394
}
362395

363-
return credentials
396+
return credentials, nil
364397
}

pkg/controller/controller_test.go

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type csiConnection struct {
3636
}
3737

3838
func New(address string, timeout time.Duration) (csiConnection, error) {
39-
conn, err := connect(address, timeout)
39+
conn, err := Connect(address, timeout)
4040
if err != nil {
4141
return csiConnection{}, err
4242
}
@@ -70,6 +70,64 @@ func createMockServer(t *testing.T) (*gomock.Controller,
7070
return mockController, drv, identityServer, controllerServer, csiConn, nil
7171
}
7272

73+
func TestGetPluginName(t *testing.T) {
74+
test := struct {
75+
name string
76+
output []*csi.GetPluginInfoResponse
77+
}{
78+
name: "success",
79+
output: []*csi.GetPluginInfoResponse{
80+
{
81+
Name: "csi/example-1",
82+
VendorVersion: "0.2.0",
83+
Manifest: map[string]string{
84+
"hello": "world",
85+
},
86+
},
87+
{
88+
Name: "csi/example-2",
89+
VendorVersion: "0.2.0",
90+
Manifest: map[string]string{
91+
"hello": "world",
92+
},
93+
},
94+
},
95+
}
96+
97+
mockController, driver, identityServer, _, csiConn, err := createMockServer(t)
98+
if err != nil {
99+
t.Fatal(err)
100+
}
101+
defer mockController.Finish()
102+
defer driver.Stop()
103+
104+
in := &csi.GetPluginInfoRequest{}
105+
out := test.output[0]
106+
107+
identityServer.EXPECT().GetPluginInfo(gomock.Any(), in).Return(out, nil).Times(1)
108+
oldName, err := getDriverName(csiConn.conn, timeout)
109+
if err != nil {
110+
t.Errorf("test %q: Failed to get driver's name", test.name)
111+
}
112+
if oldName != test.output[0].Name {
113+
t.Errorf("test %s: failed, expected %s got %s", test.name, test.output[0].Name, oldName)
114+
}
115+
116+
out = test.output[1]
117+
identityServer.EXPECT().GetPluginInfo(gomock.Any(), in).Return(out, nil).Times(1)
118+
newName, err := getDriverName(csiConn.conn, timeout)
119+
if err != nil {
120+
t.Errorf("test %s: Failed to get driver's name", test.name)
121+
}
122+
if newName != test.output[1].Name {
123+
t.Errorf("test %q: failed, expected %s got %s", test.name, test.output[1].Name, newName)
124+
}
125+
126+
if oldName == newName {
127+
t.Errorf("test: %s failed, driver's names should not match", test.name)
128+
}
129+
}
130+
73131
func TestSupportsControllerCreateVolume(t *testing.T) {
74132

75133
tests := []struct {

0 commit comments

Comments
 (0)