Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
0d2af70e
Commit
0d2af70e
authored
Feb 21, 2017
by
Chakravarthy Nelluri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for attacher/detacher interface in Flex volume
parent
46b20acb
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
1928 additions
and
448 deletions
+1928
-448
lvm
examples/volumes/flexvolume/lvm
+61
-16
nfs
examples/volumes/flexvolume/nfs
+120
-0
nginx-nfs.yaml
examples/volumes/flexvolume/nginx-nfs.yaml
+22
-0
nginx.yaml
examples/volumes/flexvolume/nginx.yaml
+1
-1
prober.go
pkg/kubelet/prober/prober.go
+4
-0
exec_test.go
pkg/probe/exec/exec_test.go
+2
-0
exec.go
pkg/util/exec/exec.go
+21
-0
fake_exec.go
pkg/util/exec/fake_exec.go
+4
-0
BUILD
pkg/volume/flexvolume/BUILD
+23
-4
OWNERS
pkg/volume/flexvolume/OWNERS
+2
-0
attacher-defaults.go
pkg/volume/flexvolume/attacher-defaults.go
+73
-0
attacher.go
pkg/volume/flexvolume/attacher.go
+120
-0
attacher_test.go
pkg/volume/flexvolume/attacher_test.go
+74
-0
common_test.go
pkg/volume/flexvolume/common_test.go
+139
-0
detacher-defaults.go
pkg/volume/flexvolume/detacher-defaults.go
+45
-0
detacher.go
pkg/volume/flexvolume/detacher.go
+97
-0
detacher_test.go
pkg/volume/flexvolume/detacher_test.go
+43
-0
driver-call.go
pkg/volume/flexvolume/driver-call.go
+224
-0
flexvolume.go
pkg/volume/flexvolume/flexvolume.go
+0
-0
flexvolume_test.go
pkg/volume/flexvolume/flexvolume_test.go
+11
-206
flexvolume_util.go
pkg/volume/flexvolume/flexvolume_util.go
+0
-221
mounter-defaults.go
pkg/volume/flexvolume/mounter-defaults.go
+61
-0
mounter.go
pkg/volume/flexvolume/mounter.go
+104
-0
mounter_test.go
pkg/volume/flexvolume/mounter_test.go
+52
-0
plugin-defaults.go
pkg/volume/flexvolume/plugin-defaults.go
+34
-0
plugin.go
pkg/volume/flexvolume/plugin.go
+191
-0
plugin_test.go
pkg/volume/flexvolume/plugin_test.go
+56
-0
probe.go
pkg/volume/flexvolume/probe.go
+50
-0
unmounter-defaults.go
pkg/volume/flexvolume/unmounter-defaults.go
+29
-0
unmounter.go
pkg/volume/flexvolume/unmounter.go
+79
-0
unmounter_test.go
pkg/volume/flexvolume/unmounter_test.go
+37
-0
util.go
pkg/volume/flexvolume/util.go
+101
-0
volume.go
pkg/volume/flexvolume/volume.go
+48
-0
No files found.
examples/volumes/flexvolume/lvm
View file @
0d2af70e
...
@@ -19,10 +19,13 @@
...
@@ -19,10 +19,13 @@
usage
()
{
usage
()
{
err
"Invalid usage. Usage: "
err
"Invalid usage. Usage: "
err
"
\t
$0
init"
err
"
\t
$0
init"
err
"
\t
$0
attach <json params>"
err
"
\t
$0
attach <json params> <nodename>"
err
"
\t
$0
detach <mount device>"
err
"
\t
$0
detach <mount device> <nodename>"
err
"
\t
$0
mount <mount dir> <mount device> <json params>"
err
"
\t
$0
waitforattach <mount device> <json params>"
err
"
\t
$0
unmount <mount dir>"
err
"
\t
$0
mountdevice <mount dir> <mount device> <json params>"
err
"
\t
$0
unmountdevice <mount dir>"
err
"
\t
$0
getvolumename <json params>"
err
"
\t
$0
isattached <json params> <nodename>"
exit
1
exit
1
}
}
...
@@ -43,16 +46,23 @@ ismounted() {
...
@@ -43,16 +46,23 @@ ismounted() {
fi
fi
}
}
attach
()
{
getdevice
()
{
VOLUMEID
=
$(
echo
$1
| jq
-r
'.volumeID'
)
VOLUMEID
=
$(
echo
${
JSON_PARAMS
}
| jq
-r
'.volumeID'
)
SIZE
=
$(
echo
$1
| jq
-r
'.size'
)
VG
=
$(
echo
${
JSON_PARAMS
}
|jq
-r
'.volumegroup'
)
VG
=
$(
echo
$1
|jq
-r
'.volumegroup'
)
# LVM substitutes - with --
# LVM substitutes - with --
VOLUMEID
=
`
echo
$VOLUMEID
|sed s/-/--/g
`
VOLUMEID
=
`
echo
$VOLUMEID
|sed s/-/--/g
`
VG
=
`
echo
$VG
|sed s/-/--/g
`
VG
=
`
echo
$VG
|sed s/-/--/g
`
DMDEV
=
"/dev/mapper/
${
VG
}
-
${
VOLUMEID
}
"
DMDEV
=
"/dev/mapper/
${
VG
}
-
${
VOLUMEID
}
"
echo
${
DMDEV
}
}
attach
()
{
JSON_PARAMS
=
$1
SIZE
=
$(
echo
$1
| jq
-r
'.size'
)
DMDEV
=
$(
getdevice
)
if
[
!
-b
"
${
DMDEV
}
"
]
;
then
if
[
!
-b
"
${
DMDEV
}
"
]
;
then
err
"{
\"
status
\"
:
\"
Failure
\"
,
\"
message
\"
:
\"
Volume
${
VOLUMEID
}
does not exist
\"
}"
err
"{
\"
status
\"
:
\"
Failure
\"
,
\"
message
\"
:
\"
Volume
${
VOLUMEID
}
does not exist
\"
}"
exit
1
exit
1
...
@@ -66,7 +76,12 @@ detach() {
...
@@ -66,7 +76,12 @@ detach() {
exit
0
exit
0
}
}
domount
()
{
waitforattach
()
{
shift
attach
$*
}
domountdevice
()
{
MNTPATH
=
$1
MNTPATH
=
$1
DMDEV
=
$2
DMDEV
=
$2
FSTYPE
=
$(
echo
$3
|jq
-r
'.["kubernetes.io/fsType"]'
)
FSTYPE
=
$(
echo
$3
|jq
-r
'.["kubernetes.io/fsType"]'
)
...
@@ -101,8 +116,13 @@ domount() {
...
@@ -101,8 +116,13 @@ domount() {
exit
0
exit
0
}
}
unmount
()
{
unmount
device
()
{
MNTPATH
=
$1
MNTPATH
=
$1
if
[
!
-d
${
MNTPATH
}
]
;
then
log
"{
\"
status
\"
:
\"
Success
\"
}"
exit
0
fi
if
[
$(
ismounted
)
-eq
0
]
;
then
if
[
$(
ismounted
)
-eq
0
]
;
then
log
"{
\"
status
\"
:
\"
Success
\"
}"
log
"{
\"
status
\"
:
\"
Success
\"
}"
exit
0
exit
0
...
@@ -113,12 +133,27 @@ unmount() {
...
@@ -113,12 +133,27 @@ unmount() {
err
"{
\"
status
\"
:
\"
Failed
\"
,
\"
message
\"
:
\"
Failed to unmount volume at
${
MNTPATH
}
\"
}"
err
"{
\"
status
\"
:
\"
Failed
\"
,
\"
message
\"
:
\"
Failed to unmount volume at
${
MNTPATH
}
\"
}"
exit
1
exit
1
fi
fi
rmdir
${
MNTPATH
}
&> /dev/null
log
"{
\"
status
\"
:
\"
Success
\"
}"
log
"{
\"
status
\"
:
\"
Success
\"
}"
exit
0
exit
0
}
}
getvolumename
()
{
JSON_PARAMS
=
$1
DMDEV
=
$(
getdevice
)
# get lvm device UUID
UUID
=
`
lvs
-o
lv_uuid
--noheadings
${
DMDEV
}
2>/dev/null|tr
-d
" "
`
log
"{
\"
status
\"
:
\"
Success
\"
,
\"
volumeName
\"
:
\"
${
UUID
}
\"
}"
exit
0
}
isattached
()
{
log
"{
\"
status
\"
:
\"
Success
\"
,
\"
attached
\"
:true}"
exit
0
}
op
=
$1
op
=
$1
if
[
"
$op
"
=
"init"
]
;
then
if
[
"
$op
"
=
"init"
]
;
then
...
@@ -139,14 +174,24 @@ case "$op" in
...
@@ -139,14 +174,24 @@ case "$op" in
detach
)
detach
)
detach
$*
detach
$*
;;
;;
mount
)
waitforattach
)
domount
$*
waitforattach
$*
;;
;;
unmount
)
mountdevice
)
unmount
$*
domountdevice
$*
;;
;;
unmountdevice
)
unmountdevice
$*
;;
getvolumename
)
getvolumename
$*
;;
isattached
)
isattached
$*
;;
*
)
*
)
usage
err
"{
\"
status
\"
:
\"
Not supported
\"
}"
exit
1
esac
esac
exit
1
exit
1
examples/volumes/flexvolume/nfs
0 → 100755
View file @
0d2af70e
#!/bin/bash
# Copyright 2015 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.
# Notes:
# - Please install "jq" package before using this driver.
usage
()
{
err
"Invalid usage. Usage: "
err
"
\t
$0
init"
err
"
\t
$0
mount <mount dir> <json params>"
err
"
\t
$0
unmount <mount dir>"
err
"
\t
$0
getvolumename <json params>"
exit
1
}
err
()
{
echo
-ne
$*
1>&2
}
log
()
{
echo
-ne
$*
>
&1
}
ismounted
()
{
MOUNT
=
`
findmnt
-n
${
MNTPATH
}
2>/dev/null |
cut
-d
' '
-f1
`
if
[
"
${
MOUNT
}
"
==
"
${
MNTPATH
}
"
]
;
then
echo
"1"
else
echo
"0"
fi
}
domount
()
{
MNTPATH
=
$1
NFS_SERVER
=
$(
echo
$2
| jq
-r
'.server'
)
SHARE
=
$(
echo
$2
| jq
-r
'.share'
)
if
[
$(
ismounted
)
-eq
1
]
;
then
log
"{
\"
status
\"
:
\"
Success
\"
}"
exit
0
fi
mkdir
-p
${
MNTPATH
}
&> /dev/null
mount
-t
nfs
${
NFS_SERVER
}
:/
${
SHARE
}
${
MNTPATH
}
&> /dev/null
if
[
$?
-ne
0
]
;
then
err
"{
\"
status
\"
:
\"
Failure
\"
,
\"
message
\"
:
\"
Failed to mount
${
NFS_SERVER
}
:
${
SHARE
}
at
${
MNTPATH
}
\"
}"
exit
1
fi
log
"{
\"
status
\"
:
\"
Success
\"
}"
exit
0
}
unmount
()
{
MNTPATH
=
$1
if
[
$(
ismounted
)
-eq
0
]
;
then
log
"{
\"
status
\"
:
\"
Success
\"
}"
exit
0
fi
umount
${
MNTPATH
}
&> /dev/null
if
[
$?
-ne
0
]
;
then
err
"{
\"
status
\"
:
\"
Failed
\"
,
\"
message
\"
:
\"
Failed to unmount volume at
${
MNTPATH
}
\"
}"
exit
1
fi
log
"{
\"
status
\"
:
\"
Success
\"
}"
exit
0
}
getvolumename
()
{
NFS_SERVER
=
$(
echo
$1
| jq
-r
'.server'
)
SHARE
=
$(
echo
$1
| jq
-r
'.share'
)
log
"{
\"
status
\"
:
\"
Success
\"
,
\"
volumeName
\"
:
\"
${
NFS_SERVER
}
/
${
SHARE
}
\"
}"
exit
0
}
op
=
$1
if
[
"
$op
"
=
"init"
]
;
then
log
"{
\"
status
\"
:
\"
Success
\"
}"
exit
0
fi
if
[
$#
-lt
2
]
;
then
usage
fi
shift
case
"
$op
"
in
mount
)
domount
$*
;;
unmount
)
unmount
$*
;;
getvolumename
)
getvolumename
$*
;;
*
)
err
"{
\"
status
\"
:
\"
Not supported
\"
}"
exit
1
esac
exit
1
examples/volumes/flexvolume/nginx-nfs.yaml
0 → 100644
View file @
0d2af70e
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
nginx-nfs
namespace
:
default
spec
:
containers
:
-
name
:
nginx-nfs
image
:
nginx
volumeMounts
:
-
name
:
test
mountPath
:
/data
ports
:
-
containerPort
:
80
volumes
:
-
name
:
test
flexVolume
:
driver
:
"
k8s/nfs"
fsType
:
"
nfs"
options
:
server
:
"
172.16.0.25"
share
:
"
dws_nas_scratch"
examples/volumes/flexvolume/nginx.yaml
View file @
0d2af70e
...
@@ -2,6 +2,7 @@ apiVersion: v1
...
@@ -2,6 +2,7 @@ apiVersion: v1
kind
:
Pod
kind
:
Pod
metadata
:
metadata
:
name
:
nginx
name
:
nginx
namespace
:
default
spec
:
spec
:
containers
:
containers
:
-
name
:
nginx
-
name
:
nginx
...
@@ -20,4 +21,3 @@ spec:
...
@@ -20,4 +21,3 @@ spec:
volumeID
:
"
vol1"
volumeID
:
"
vol1"
size
:
"
1000m"
size
:
"
1000m"
volumegroup
:
"
kube_vg"
volumegroup
:
"
kube_vg"
pkg/kubelet/prober/prober.go
View file @
0d2af70e
...
@@ -251,3 +251,7 @@ func (eic execInContainer) SetStdin(in io.Reader) {
...
@@ -251,3 +251,7 @@ func (eic execInContainer) SetStdin(in io.Reader) {
func
(
eic
execInContainer
)
SetStdout
(
out
io
.
Writer
)
{
func
(
eic
execInContainer
)
SetStdout
(
out
io
.
Writer
)
{
//unimplemented
//unimplemented
}
}
func
(
eic
execInContainer
)
Stop
()
{
//unimplemented
}
pkg/probe/exec/exec_test.go
View file @
0d2af70e
...
@@ -44,6 +44,8 @@ func (f *FakeCmd) SetStdin(in io.Reader) {}
...
@@ -44,6 +44,8 @@ func (f *FakeCmd) SetStdin(in io.Reader) {}
func
(
f
*
FakeCmd
)
SetStdout
(
out
io
.
Writer
)
{}
func
(
f
*
FakeCmd
)
SetStdout
(
out
io
.
Writer
)
{}
func
(
f
*
FakeCmd
)
Stop
()
{}
type
fakeExitError
struct
{
type
fakeExitError
struct
{
exited
bool
exited
bool
statusCode
int
statusCode
int
...
...
pkg/util/exec/exec.go
View file @
0d2af70e
...
@@ -20,6 +20,7 @@ import (
...
@@ -20,6 +20,7 @@ import (
"io"
"io"
osexec
"os/exec"
osexec
"os/exec"
"syscall"
"syscall"
"time"
)
)
// ErrExecutableNotFound is returned if the executable is not found.
// ErrExecutableNotFound is returned if the executable is not found.
...
@@ -48,6 +49,11 @@ type Cmd interface {
...
@@ -48,6 +49,11 @@ type Cmd interface {
SetDir
(
dir
string
)
SetDir
(
dir
string
)
SetStdin
(
in
io
.
Reader
)
SetStdin
(
in
io
.
Reader
)
SetStdout
(
out
io
.
Writer
)
SetStdout
(
out
io
.
Writer
)
// Stops the command by sending SIGTERM. It is not guaranteed the
// process will stop before this function returns. If the process is not
// responding, an internal timer function will send a SIGKILL to force
// terminate after 10 seconds.
Stop
()
}
}
// ExitError is an interface that presents an API similar to os.ProcessState, which is
// ExitError is an interface that presents an API similar to os.ProcessState, which is
...
@@ -110,6 +116,21 @@ func (cmd *cmdWrapper) Output() ([]byte, error) {
...
@@ -110,6 +116,21 @@ func (cmd *cmdWrapper) Output() ([]byte, error) {
return
out
,
nil
return
out
,
nil
}
}
// Stop is part of the Cmd interface.
func
(
cmd
*
cmdWrapper
)
Stop
()
{
c
:=
(
*
osexec
.
Cmd
)(
cmd
)
if
c
.
ProcessState
.
Exited
()
{
return
}
c
.
Process
.
Signal
(
syscall
.
SIGTERM
)
time
.
AfterFunc
(
10
*
time
.
Second
,
func
()
{
if
c
.
ProcessState
.
Exited
()
{
return
}
c
.
Process
.
Signal
(
syscall
.
SIGKILL
)
})
}
func
handleError
(
err
error
)
error
{
func
handleError
(
err
error
)
error
{
if
ee
,
ok
:=
err
.
(
*
osexec
.
ExitError
);
ok
{
if
ee
,
ok
:=
err
.
(
*
osexec
.
ExitError
);
ok
{
// Force a compile fail if exitErrorWrapper can't convert to ExitError.
// Force a compile fail if exitErrorWrapper can't convert to ExitError.
...
...
pkg/util/exec/fake_exec.go
View file @
0d2af70e
...
@@ -90,6 +90,10 @@ func (fake *FakeCmd) Output() ([]byte, error) {
...
@@ -90,6 +90,10 @@ func (fake *FakeCmd) Output() ([]byte, error) {
return
nil
,
fmt
.
Errorf
(
"unimplemented"
)
return
nil
,
fmt
.
Errorf
(
"unimplemented"
)
}
}
func
(
fake
*
FakeCmd
)
Stop
()
{
// no-op
}
// A simple fake ExitError type.
// A simple fake ExitError type.
type
FakeExitError
struct
{
type
FakeExitError
struct
{
Status
int
Status
int
...
...
pkg/volume/flexvolume/BUILD
View file @
0d2af70e
...
@@ -11,8 +11,20 @@ load(
...
@@ -11,8 +11,20 @@ load(
go_library(
go_library(
name = "go_default_library",
name = "go_default_library",
srcs = [
srcs = [
"flexvolume.go",
"attacher.go",
"flexvolume_util.go",
"attacher-defaults.go",
"detacher.go",
"detacher-defaults.go",
"driver-call.go",
"mounter.go",
"mounter-defaults.go",
"plugin.go",
"plugin-defaults.go",
"probe.go",
"unmounter.go",
"unmounter-defaults.go",
"util.go",
"volume.go",
],
],
tags = ["automanaged"],
tags = ["automanaged"],
deps = [
deps = [
...
@@ -23,14 +35,21 @@ go_library(
...
@@ -23,14 +35,21 @@ go_library(
"//pkg/volume:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/util:go_default_library",
"//pkg/volume/util:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/types",
"//vendor:k8s.io/apimachinery/pkg/types",
],
],
)
)
go_test(
go_test(
name = "go_default_test",
name = "go_default_test",
srcs = ["flexvolume_test.go"],
srcs = [
"attacher_test.go",
"common_test.go",
"detacher_test.go",
"flexvolume_test.go",
"mounter_test.go",
"plugin_test.go",
"unmounter_test.go",
],
library = ":go_default_library",
library = ":go_default_library",
tags = ["automanaged"],
tags = ["automanaged"],
deps = [
deps = [
...
...
pkg/volume/flexvolume/OWNERS
View file @
0d2af70e
approvers:
approvers:
- chakri-nelluri
- chakri-nelluri
- saad-ali
- saad-ali
- MikaelCluseau
reviewers:
reviewers:
- ivan4th
- ivan4th
- rata
- rata
...
@@ -20,3 +21,4 @@ reviewers:
...
@@ -20,3 +21,4 @@ reviewers:
- rkouj
- rkouj
- msau42
- msau42
- chakri-nelluri
- chakri-nelluri
- MikaelCluseau
pkg/volume/flexvolume/attacher-defaults.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"fmt"
"path"
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/util/exec"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
)
type
attacherDefaults
flexVolumeAttacher
// Attach is part of the volume.Attacher interface
func
(
a
*
attacherDefaults
)
Attach
(
spec
*
volume
.
Spec
,
hostName
types
.
NodeName
)
(
string
,
error
)
{
glog
.
Warning
(
logPrefix
(
a
.
plugin
),
"using default Attach for volume "
,
spec
.
Name
,
", host "
,
hostName
)
return
""
,
nil
}
// WaitForAttach is part of the volume.Attacher interface
func
(
a
*
attacherDefaults
)
WaitForAttach
(
spec
*
volume
.
Spec
,
devicePath
string
,
timeout
time
.
Duration
)
(
string
,
error
)
{
glog
.
Warning
(
logPrefix
(
a
.
plugin
),
"using default WaitForAttach for volume "
,
spec
.
Name
,
", device "
,
devicePath
)
return
devicePath
,
nil
}
// GetDeviceMountPath is part of the volume.Attacher interface
func
(
a
*
attacherDefaults
)
GetDeviceMountPath
(
spec
*
volume
.
Spec
,
mountsDir
string
)
(
string
,
error
)
{
glog
.
Warning
(
logPrefix
(
a
.
plugin
),
"using default GetDeviceMountPath for volume "
,
spec
.
Name
,
", mountsDir "
,
mountsDir
)
volumeName
,
err
:=
a
.
plugin
.
GetVolumeName
(
spec
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"GetVolumeName failed from GetDeviceMountPath: %s"
,
err
)
}
return
path
.
Join
(
mountsDir
,
volumeName
),
nil
}
// MountDevice is part of the volume.Attacher interface
func
(
a
*
attacherDefaults
)
MountDevice
(
spec
*
volume
.
Spec
,
devicePath
string
,
deviceMountPath
string
,
mounter
mount
.
Interface
)
error
{
glog
.
Warning
(
logPrefix
(
a
.
plugin
),
"using default MountDevice for volume "
,
spec
.
Name
,
", device "
,
devicePath
,
", deviceMountPath "
,
deviceMountPath
)
volSource
,
readOnly
:=
getVolumeSource
(
spec
)
options
:=
make
([]
string
,
0
)
if
readOnly
{
options
=
append
(
options
,
"ro"
)
}
else
{
options
=
append
(
options
,
"rw"
)
}
diskMounter
:=
&
mount
.
SafeFormatAndMount
{
Interface
:
mounter
,
Runner
:
exec
.
New
()}
return
diskMounter
.
FormatAndMount
(
devicePath
,
deviceMountPath
,
volSource
.
FSType
,
options
)
}
pkg/volume/flexvolume/attacher.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"path"
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/volume"
)
type
flexVolumeAttacher
struct
{
plugin
*
flexVolumePlugin
}
var
_
volume
.
Attacher
=
&
flexVolumeAttacher
{}
// Attach is part of the volume.Attacher interface
func
(
a
*
flexVolumeAttacher
)
Attach
(
spec
*
volume
.
Spec
,
hostName
types
.
NodeName
)
(
string
,
error
)
{
call
:=
a
.
plugin
.
NewDriverCall
(
attachCmd
)
call
.
AppendSpec
(
spec
,
a
.
plugin
.
host
,
nil
)
call
.
Append
(
string
(
hostName
))
status
,
err
:=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
return
(
*
attacherDefaults
)(
a
)
.
Attach
(
spec
,
hostName
)
}
else
if
err
!=
nil
{
return
""
,
err
}
return
status
.
DevicePath
,
err
}
// WaitForAttach is part of the volume.Attacher interface
func
(
a
*
flexVolumeAttacher
)
WaitForAttach
(
spec
*
volume
.
Spec
,
devicePath
string
,
timeout
time
.
Duration
)
(
string
,
error
)
{
call
:=
a
.
plugin
.
NewDriverCallWithTimeout
(
waitForAttachCmd
,
timeout
)
call
.
Append
(
devicePath
)
call
.
AppendSpec
(
spec
,
a
.
plugin
.
host
,
nil
)
status
,
err
:=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
return
(
*
attacherDefaults
)(
a
)
.
WaitForAttach
(
spec
,
devicePath
,
timeout
)
}
else
if
err
!=
nil
{
return
""
,
err
}
return
status
.
DevicePath
,
nil
}
// GetDeviceMountPath is part of the volume.Attacher interface
func
(
a
*
flexVolumeAttacher
)
GetDeviceMountPath
(
spec
*
volume
.
Spec
)
(
string
,
error
)
{
mountsDir
:=
path
.
Join
(
a
.
plugin
.
host
.
GetPluginDir
(
flexVolumePluginName
),
a
.
plugin
.
driverName
,
"mounts"
)
return
(
*
attacherDefaults
)(
a
)
.
GetDeviceMountPath
(
spec
,
mountsDir
)
}
// MountDevice is part of the volume.Attacher interface
func
(
a
*
flexVolumeAttacher
)
MountDevice
(
spec
*
volume
.
Spec
,
devicePath
string
,
deviceMountPath
string
)
error
{
// Mount only once.
alreadyMounted
,
err
:=
prepareForMount
(
a
.
plugin
.
host
.
GetMounter
(),
deviceMountPath
)
if
err
!=
nil
{
return
err
}
if
alreadyMounted
{
return
nil
}
call
:=
a
.
plugin
.
NewDriverCall
(
mountDeviceCmd
)
call
.
Append
(
deviceMountPath
)
call
.
Append
(
devicePath
)
call
.
AppendSpec
(
spec
,
a
.
plugin
.
host
,
nil
)
_
,
err
=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
// Devicepath is empty if the plugin does not support attach calls. Ignore mountDevice calls if the
// plugin does not implement attach interface.
if
devicePath
!=
""
{
return
(
*
attacherDefaults
)(
a
)
.
MountDevice
(
spec
,
devicePath
,
deviceMountPath
,
a
.
plugin
.
host
.
GetMounter
())
}
else
{
return
nil
}
}
return
err
}
func
(
a
*
flexVolumeAttacher
)
VolumesAreAttached
(
specs
[]
*
volume
.
Spec
,
nodeName
types
.
NodeName
)
(
map
[
*
volume
.
Spec
]
bool
,
error
)
{
volumesAttachedCheck
:=
make
(
map
[
*
volume
.
Spec
]
bool
)
for
_
,
spec
:=
range
specs
{
volumesAttachedCheck
[
spec
]
=
true
call
:=
a
.
plugin
.
NewDriverCall
(
isAttached
)
call
.
AppendSpec
(
spec
,
a
.
plugin
.
host
,
nil
)
call
.
Append
(
string
(
nodeName
))
status
,
err
:=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
return
nil
,
nil
}
else
if
err
==
nil
{
if
!
status
.
Attached
{
volumesAttachedCheck
[
spec
]
=
false
glog
.
V
(
2
)
.
Infof
(
"VolumesAreAttached: check volume (%q) is no longer attached"
,
spec
.
Name
())
}
}
}
return
volumesAttachedCheck
,
nil
}
pkg/volume/flexvolume/attacher_test.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"k8s.io/kubernetes/pkg/volume"
"testing"
"time"
)
func
TestAttach
(
t
*
testing
.
T
)
{
spec
:=
fakeVolumeSpec
()
plugin
,
_
:=
testPlugin
()
plugin
.
runner
=
fakeRunner
(
assertDriverCall
(
t
,
notSupportedOutput
(),
attachCmd
,
specJson
(
plugin
,
spec
,
nil
),
"localhost"
),
)
a
,
_
:=
plugin
.
NewAttacher
()
a
.
Attach
(
spec
,
"localhost"
)
}
func
TestWaitForAttach
(
t
*
testing
.
T
)
{
spec
:=
fakeVolumeSpec
()
plugin
,
_
:=
testPlugin
()
plugin
.
runner
=
fakeRunner
(
assertDriverCall
(
t
,
notSupportedOutput
(),
waitForAttachCmd
,
"/dev/sdx"
,
specJson
(
plugin
,
spec
,
nil
)),
)
a
,
_
:=
plugin
.
NewAttacher
()
a
.
WaitForAttach
(
spec
,
"/dev/sdx"
,
1
*
time
.
Second
)
}
func
TestMountDevice
(
t
*
testing
.
T
)
{
spec
:=
fakeVolumeSpec
()
plugin
,
rootDir
:=
testPlugin
()
plugin
.
runner
=
fakeRunner
(
assertDriverCall
(
t
,
notSupportedOutput
(),
mountDeviceCmd
,
rootDir
+
"/mount-dir"
,
"/dev/sdx"
,
specJson
(
plugin
,
spec
,
nil
)),
)
a
,
_
:=
plugin
.
NewAttacher
()
a
.
MountDevice
(
spec
,
"/dev/sdx"
,
rootDir
+
"/mount-dir"
)
}
func
TestIsVolumeAttached
(
t
*
testing
.
T
)
{
spec
:=
fakeVolumeSpec
()
plugin
,
_
:=
testPlugin
()
plugin
.
runner
=
fakeRunner
(
assertDriverCall
(
t
,
notSupportedOutput
(),
isAttached
,
specJson
(
plugin
,
spec
,
nil
),
"localhost"
),
)
a
,
_
:=
plugin
.
NewAttacher
()
specs
:=
[]
*
volume
.
Spec
{
spec
}
a
.
VolumesAreAttached
(
specs
,
"localhost"
)
}
pkg/volume/flexvolume/common_test.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"encoding/json"
"testing"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
utiltesting
"k8s.io/client-go/util/testing"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/util/exec"
"k8s.io/kubernetes/pkg/volume"
volumetesting
"k8s.io/kubernetes/pkg/volume/testing"
)
func
testPlugin
()
(
*
flexVolumePlugin
,
string
)
{
rootDir
,
err
:=
utiltesting
.
MkTmpdir
(
"flexvolume_test"
)
if
err
!=
nil
{
panic
(
"error creating temp dir: "
+
err
.
Error
())
}
return
&
flexVolumePlugin
{
driverName
:
"test"
,
execPath
:
"/plugin"
,
host
:
volumetesting
.
NewFakeVolumeHost
(
rootDir
,
nil
,
nil
),
unsupportedCommands
:
[]
string
{},
},
rootDir
}
func
assertDriverCall
(
t
*
testing
.
T
,
output
exec
.
FakeCombinedOutputAction
,
expectedCommand
string
,
expectedArgs
...
string
)
exec
.
FakeCommandAction
{
return
func
(
cmd
string
,
args
...
string
)
exec
.
Cmd
{
if
cmd
!=
"/plugin/test"
{
t
.
Errorf
(
"Wrong executable called: got %v, expected %v"
,
cmd
,
"/plugin/test"
)
}
if
args
[
0
]
!=
expectedCommand
{
t
.
Errorf
(
"Wrong command called: got %v, expected %v"
,
args
[
0
],
expectedCommand
)
}
cmdArgs
:=
args
[
1
:
]
if
!
sameArgs
(
cmdArgs
,
expectedArgs
)
{
t
.
Errorf
(
"Wrong args for %s: got %v, expected %v"
,
args
[
0
],
cmdArgs
,
expectedArgs
)
}
return
&
exec
.
FakeCmd
{
Argv
:
args
,
CombinedOutputScript
:
[]
exec
.
FakeCombinedOutputAction
{
output
},
}
}
}
func
fakeRunner
(
fakeCommands
...
exec
.
FakeCommandAction
)
exec
.
Interface
{
return
&
exec
.
FakeExec
{
CommandScript
:
fakeCommands
,
}
}
func
fakeResultOutput
(
result
interface
{})
exec
.
FakeCombinedOutputAction
{
return
func
()
([]
byte
,
error
)
{
bytes
,
err
:=
json
.
Marshal
(
result
)
if
err
!=
nil
{
panic
(
"Unable to marshal result: "
+
err
.
Error
())
}
return
bytes
,
nil
}
}
func
successOutput
()
exec
.
FakeCombinedOutputAction
{
return
fakeResultOutput
(
&
DriverStatus
{
StatusSuccess
,
""
,
""
,
""
,
true
})
}
func
notSupportedOutput
()
exec
.
FakeCombinedOutputAction
{
return
fakeResultOutput
(
&
DriverStatus
{
StatusNotSupported
,
""
,
""
,
""
,
false
})
}
func
sameArgs
(
args
,
expectedArgs
[]
string
)
bool
{
if
len
(
args
)
!=
len
(
expectedArgs
)
{
return
false
}
for
i
,
v
:=
range
args
{
if
v
!=
expectedArgs
[
i
]
{
return
false
}
}
return
true
}
func
fakeVolumeSpec
()
*
volume
.
Spec
{
vol
:=
&
v1
.
Volume
{
Name
:
"vol1"
,
VolumeSource
:
v1
.
VolumeSource
{
FlexVolume
:
&
v1
.
FlexVolumeSource
{
Driver
:
"kubernetes.io/fakeAttacher"
,
ReadOnly
:
false
,
},
},
}
return
volume
.
NewSpecFromVolume
(
vol
)
}
func
fakePersistentVolumeSpec
()
*
volume
.
Spec
{
vol
:=
&
v1
.
PersistentVolume
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"vol1"
,
},
Spec
:
v1
.
PersistentVolumeSpec
{
PersistentVolumeSource
:
v1
.
PersistentVolumeSource
{
FlexVolume
:
&
v1
.
FlexVolumeSource
{
Driver
:
"kubernetes.io/fakeAttacher"
,
ReadOnly
:
false
,
},
},
},
}
return
volume
.
NewSpecFromPersistentVolume
(
vol
,
false
)
}
func
specJson
(
plugin
*
flexVolumePlugin
,
spec
*
volume
.
Spec
,
extraOptions
map
[
string
]
string
)
string
{
o
,
err
:=
NewOptionsForDriver
(
spec
,
plugin
.
host
,
extraOptions
)
if
err
!=
nil
{
panic
(
"Failed to convert spec: "
+
err
.
Error
())
}
bytes
,
err
:=
json
.
Marshal
(
o
)
if
err
!=
nil
{
panic
(
"Unable to marshal result: "
+
err
.
Error
())
}
return
string
(
bytes
)
}
pkg/volume/flexvolume/detacher-defaults.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/volume/util"
)
type
detacherDefaults
flexVolumeDetacher
// Detach is part of the volume.Detacher interface.
func
(
d
*
detacherDefaults
)
Detach
(
deviceName
string
,
hostName
types
.
NodeName
)
error
{
glog
.
Warning
(
logPrefix
(
d
.
plugin
),
"using default Detach for device "
,
deviceName
,
", host "
,
hostName
)
return
nil
}
// WaitForDetach is part of the volume.Detacher interface.
func
(
d
*
detacherDefaults
)
WaitForDetach
(
devicePath
string
,
timeout
time
.
Duration
)
error
{
glog
.
Warning
(
logPrefix
(
d
.
plugin
),
"using default WaitForDetach for device "
,
devicePath
)
return
nil
}
// UnmountDevice is part of the volume.Detacher interface.
func
(
d
*
detacherDefaults
)
UnmountDevice
(
deviceMountPath
string
)
error
{
glog
.
Warning
(
logPrefix
(
d
.
plugin
),
"using default UnmountDevice for device mount path "
,
deviceMountPath
)
return
util
.
UnmountPath
(
deviceMountPath
,
d
.
plugin
.
host
.
GetMounter
())
}
pkg/volume/flexvolume/detacher.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"fmt"
"os"
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
)
type
flexVolumeDetacher
struct
{
plugin
*
flexVolumePlugin
}
var
_
volume
.
Detacher
=
&
flexVolumeDetacher
{}
// Detach is part of the volume.Detacher interface.
func
(
d
*
flexVolumeDetacher
)
Detach
(
deviceName
string
,
hostName
types
.
NodeName
)
error
{
call
:=
d
.
plugin
.
NewDriverCall
(
detachCmd
)
call
.
Append
(
deviceName
)
call
.
Append
(
string
(
hostName
))
_
,
err
:=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
return
(
*
detacherDefaults
)(
d
)
.
Detach
(
deviceName
,
hostName
)
}
return
err
}
// WaitForDetach is part of the volume.Detacher interface.
func
(
d
*
flexVolumeDetacher
)
WaitForDetach
(
devicePath
string
,
timeout
time
.
Duration
)
error
{
call
:=
d
.
plugin
.
NewDriverCallWithTimeout
(
waitForDetachCmd
,
timeout
)
call
.
Append
(
devicePath
)
_
,
err
:=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
return
(
*
detacherDefaults
)(
d
)
.
WaitForDetach
(
devicePath
,
timeout
)
}
return
err
}
// UnmountDevice is part of the volume.Detacher interface.
func
(
d
*
flexVolumeDetacher
)
UnmountDevice
(
deviceMountPath
string
)
error
{
if
pathExists
,
pathErr
:=
util
.
PathExists
(
deviceMountPath
);
pathErr
!=
nil
{
return
fmt
.
Errorf
(
"Error checking if path exists: %v"
,
pathErr
)
}
else
if
!
pathExists
{
glog
.
Warningf
(
"Warning: Unmount skipped because path does not exist: %v"
,
deviceMountPath
)
return
nil
}
notmnt
,
err
:=
isNotMounted
(
d
.
plugin
.
host
.
GetMounter
(),
deviceMountPath
)
if
err
!=
nil
{
return
err
}
if
notmnt
{
glog
.
Warningf
(
"Warning: Path: %v already unmounted"
,
deviceMountPath
)
}
else
{
call
:=
d
.
plugin
.
NewDriverCall
(
unmountDeviceCmd
)
call
.
Append
(
deviceMountPath
)
_
,
err
:=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
err
=
(
*
detacherDefaults
)(
d
)
.
UnmountDevice
(
deviceMountPath
)
}
if
err
!=
nil
{
return
err
}
}
// Flexvolume driver may remove the directory. Ignore if it does.
if
pathExists
,
pathErr
:=
util
.
PathExists
(
deviceMountPath
);
pathErr
!=
nil
{
return
fmt
.
Errorf
(
"Error checking if path exists: %v"
,
pathErr
)
}
else
if
!
pathExists
{
return
nil
}
return
os
.
Remove
(
deviceMountPath
)
}
pkg/volume/flexvolume/detacher_test.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"testing"
)
func
TestDetach
(
t
*
testing
.
T
)
{
plugin
,
_
:=
testPlugin
()
plugin
.
runner
=
fakeRunner
(
assertDriverCall
(
t
,
notSupportedOutput
(),
detachCmd
,
"sdx"
,
"localhost"
),
)
d
,
_
:=
plugin
.
NewDetacher
()
d
.
Detach
(
"sdx"
,
"localhost"
)
}
func
TestUnmountDevice
(
t
*
testing
.
T
)
{
plugin
,
rootDir
:=
testPlugin
()
plugin
.
runner
=
fakeRunner
(
assertDriverCall
(
t
,
notSupportedOutput
(),
unmountDeviceCmd
,
rootDir
+
"/mount-dir"
),
)
d
,
_
:=
plugin
.
NewDetacher
()
d
.
UnmountDevice
(
rootDir
+
"/mount-dir"
)
}
pkg/volume/flexvolume/driver-call.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"encoding/json"
"errors"
"fmt"
"time"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/volume"
)
const
(
// Driver calls
initCmd
=
"init"
getVolumeNameCmd
=
"getvolumename"
isAttached
=
"isattached"
attachCmd
=
"attach"
waitForAttachCmd
=
"waitforattach"
mountDeviceCmd
=
"mountdevice"
detachCmd
=
"detach"
waitForDetachCmd
=
"waitfordetach"
unmountDeviceCmd
=
"unmountdevice"
mountCmd
=
"mount"
unmountCmd
=
"unmount"
// Option keys
optionFSType
=
"kubernetes.io/fsType"
optionReadWrite
=
"kubernetes.io/readwrite"
optionKeySecret
=
"kubernetes.io/secret"
optionFSGroup
=
"kubernetes.io/fsGroup"
optionMountsDir
=
"kubernetes.io/mountsDir"
)
const
(
// StatusSuccess represents the successful completion of command.
StatusSuccess
=
"Success"
// StatusFailed represents that the command failed.
StatusFailure
=
"Failed"
// StatusNotSupported represents that the command is not supported.
StatusNotSupported
=
"Not supported"
)
var
(
TimeoutError
=
fmt
.
Errorf
(
"Timeout"
)
)
// DriverCall implements the basic contract between FlexVolume and its driver.
// The caller is responsible for providing the required args.
type
DriverCall
struct
{
Command
string
Timeout
time
.
Duration
plugin
*
flexVolumePlugin
args
[]
string
}
func
(
plugin
*
flexVolumePlugin
)
NewDriverCall
(
command
string
)
*
DriverCall
{
return
plugin
.
NewDriverCallWithTimeout
(
command
,
0
)
}
func
(
plugin
*
flexVolumePlugin
)
NewDriverCallWithTimeout
(
command
string
,
timeout
time
.
Duration
)
*
DriverCall
{
return
&
DriverCall
{
Command
:
command
,
Timeout
:
timeout
,
plugin
:
plugin
,
args
:
[]
string
{
command
},
}
}
func
(
dc
*
DriverCall
)
Append
(
arg
string
)
{
dc
.
args
=
append
(
dc
.
args
,
arg
)
}
func
(
dc
*
DriverCall
)
AppendSpec
(
spec
*
volume
.
Spec
,
host
volume
.
VolumeHost
,
extraOptions
map
[
string
]
string
)
error
{
optionsForDriver
,
err
:=
NewOptionsForDriver
(
spec
,
host
,
extraOptions
)
if
err
!=
nil
{
return
err
}
jsonBytes
,
err
:=
json
.
Marshal
(
optionsForDriver
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Failed to marshal spec, error: %s"
,
err
.
Error
())
}
dc
.
Append
(
string
(
jsonBytes
))
return
nil
}
func
(
dc
*
DriverCall
)
Run
()
(
*
DriverStatus
,
error
)
{
if
dc
.
plugin
.
isUnsupported
(
dc
.
Command
)
{
return
nil
,
errors
.
New
(
StatusNotSupported
)
}
execPath
:=
dc
.
plugin
.
getExecutable
()
cmd
:=
dc
.
plugin
.
runner
.
Command
(
execPath
,
dc
.
args
...
)
timeout
:=
false
if
dc
.
Timeout
>
0
{
timer
:=
time
.
AfterFunc
(
dc
.
Timeout
,
func
()
{
timeout
=
true
cmd
.
Stop
()
})
defer
timer
.
Stop
()
}
output
,
execErr
:=
cmd
.
CombinedOutput
()
if
execErr
!=
nil
{
if
timeout
{
return
nil
,
TimeoutError
}
_
,
err
:=
handleCmdResponse
(
dc
.
Command
,
output
)
if
err
==
nil
{
glog
.
Errorf
(
"FlexVolume: driver bug: %s: exec error (%s) but no error in response."
,
execPath
,
execErr
)
return
nil
,
execErr
}
if
isCmdNotSupportedErr
(
err
)
{
dc
.
plugin
.
unsupported
(
dc
.
Command
)
}
else
{
glog
.
Warningf
(
"FlexVolume: driver call failed: executable: %s, args: %s, error: %s, output: %s"
,
execPath
,
dc
.
args
,
execErr
.
Error
(),
output
)
}
return
nil
,
err
}
status
,
err
:=
handleCmdResponse
(
dc
.
Command
,
output
)
if
err
!=
nil
{
if
isCmdNotSupportedErr
(
err
)
{
dc
.
plugin
.
unsupported
(
dc
.
Command
)
}
return
nil
,
err
}
return
status
,
nil
}
// OptionsForDriver represents the spec given to the driver.
type
OptionsForDriver
map
[
string
]
string
func
NewOptionsForDriver
(
spec
*
volume
.
Spec
,
host
volume
.
VolumeHost
,
extraOptions
map
[
string
]
string
)
(
OptionsForDriver
,
error
)
{
volSource
,
readOnly
:=
getVolumeSource
(
spec
)
options
:=
map
[
string
]
string
{}
options
[
optionFSType
]
=
volSource
.
FSType
if
readOnly
{
options
[
optionReadWrite
]
=
"ro"
}
else
{
options
[
optionReadWrite
]
=
"rw"
}
for
key
,
value
:=
range
extraOptions
{
options
[
key
]
=
value
}
for
key
,
value
:=
range
volSource
.
Options
{
options
[
key
]
=
value
}
return
OptionsForDriver
(
options
),
nil
}
// DriverStatus represents the return value of the driver callout.
type
DriverStatus
struct
{
// Status of the callout. One of "Success", "Failure" or "Not supported".
Status
string
`json:"status"`
// Reason for success/failure.
Message
string
`json:"message,omitempty"`
// Path to the device attached. This field is valid only for attach calls.
// ie: /dev/sdx
DevicePath
string
`json:"device,omitempty"`
// Cluster wide unique name of the volume.
VolumeName
string
`json:"volumeName,omitempty"`
// Represents volume is attached on the node
Attached
bool
`json:"attached,omitempty"`
}
// isCmdNotSupportedErr checks if the error corresponds to command not supported by
// driver.
func
isCmdNotSupportedErr
(
err
error
)
bool
{
if
err
!=
nil
&&
err
.
Error
()
==
StatusNotSupported
{
return
true
}
return
false
}
// handleCmdResponse processes the command output and returns the appropriate
// error code or message.
func
handleCmdResponse
(
cmd
string
,
output
[]
byte
)
(
*
DriverStatus
,
error
)
{
var
status
DriverStatus
if
err
:=
json
.
Unmarshal
(
output
,
&
status
);
err
!=
nil
{
glog
.
Errorf
(
"Failed to unmarshal output for command: %s, output: %s, error: %s"
,
cmd
,
string
(
output
),
err
.
Error
())
return
nil
,
err
}
else
if
status
.
Status
==
StatusNotSupported
{
glog
.
V
(
5
)
.
Infof
(
"%s command is not supported by the driver"
,
cmd
)
return
nil
,
errors
.
New
(
status
.
Status
)
}
else
if
status
.
Status
!=
StatusSuccess
{
errMsg
:=
fmt
.
Sprintf
(
"%s command failed, status: %s, reason: %s"
,
cmd
,
status
.
Status
,
status
.
Message
)
glog
.
Errorf
(
errMsg
)
return
nil
,
fmt
.
Errorf
(
"%s"
,
errMsg
)
}
return
&
status
,
nil
}
pkg/volume/flexvolume/flexvolume.go
deleted
100644 → 0
View file @
46b20acb
This diff is collapsed.
Click to expand it.
pkg/volume/flexvolume/flexvolume_test.go
View file @
0d2af70e
...
@@ -18,19 +18,14 @@ package flexvolume
...
@@ -18,19 +18,14 @@ package flexvolume
import
(
import
(
"bytes"
"bytes"
"encoding/base64"
"fmt"
"fmt"
"os"
"os"
"path"
"path"
"testing"
"testing"
"text/template"
"text/template"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
utiltesting
"k8s.io/client-go/util/testing"
utiltesting
"k8s.io/client-go/util/testing"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/util/exec"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume"
volumetest
"k8s.io/kubernetes/pkg/volume/testing"
volumetest
"k8s.io/kubernetes/pkg/volume/testing"
)
)
...
@@ -55,21 +50,22 @@ elif [ "$1" == "detach" -a $# -eq 2 ]; then
...
@@ -55,21 +50,22 @@ elif [ "$1" == "detach" -a $# -eq 2 ]; then
"status": "Success"
"status": "Success"
}'
}'
exit 0
exit 0
elif [ "$1" == "
mount
" -a $# -eq 4 ]; then
elif [ "$1" == "
getvolumename
" -a $# -eq 4 ]; then
echo -n '{
echo -n '{
"status": "Not supported"
"status": "Success",
"volume": "fakevolume"
}'
}'
exit 0
exit 0
elif [ "$1" == "
unmount
" -a $# -eq 2 ]; then
elif [ "$1" == "
isattached
" -a $# -eq 2 ]; then
echo -n '{
echo -n '{
"status": "Not supported"
"status": "Success",
"attached": true
}'
}'
exit 0
exit 0
fi
fi
echo -n '{
echo -n '{
"status": "Failure",
"status": "Not supported"
"reason": "Invalid usage"
}'
}'
exit 1
exit 1
...
@@ -85,14 +81,10 @@ if [ "$1" == "init" -a $# -eq 1 ]; then
...
@@ -85,14 +81,10 @@ if [ "$1" == "init" -a $# -eq 1 ]; then
exit 0
exit 0
fi
fi
if [ "$1" == "attach" -a $# -eq 2 ]; then
if [ "$1" == "getvolumename" -a $# -eq 2 ]; then
echo -n '{
"status": "Not supported"
}'
exit 0
elif [ "$1" == "detach" -a $# -eq 2 ]; then
echo -n '{
echo -n '{
"status": "Not supported"
"status": "Success",
"volumeName": "fakevolume"
}'
}'
exit 0
exit 0
elif [ "$1" == "mount" -a $# -eq 4 ]; then
elif [ "$1" == "mount" -a $# -eq 4 ]; then
...
@@ -126,8 +118,7 @@ elif [ "$1" == "unmount" -a $# -eq 2 ]; then
...
@@ -126,8 +118,7 @@ elif [ "$1" == "unmount" -a $# -eq 2 ]; then
fi
fi
echo -n '{
echo -n '{
"status": "Failure",
"status": "Not Supported"
"reason": "Invalid usage"
}'
}'
exit 1
exit 1
...
@@ -230,189 +221,3 @@ func contains(modes []v1.PersistentVolumeAccessMode, mode v1.PersistentVolumeAcc
...
@@ -230,189 +221,3 @@ func contains(modes []v1.PersistentVolumeAccessMode, mode v1.PersistentVolumeAcc
}
}
return
false
return
false
}
}
func
doTestPluginAttachDetach
(
t
*
testing
.
T
,
spec
*
volume
.
Spec
,
tmpDir
string
)
{
plugMgr
:=
volume
.
VolumePluginMgr
{}
installPluginUnderTest
(
t
,
"kubernetes.io"
,
"fakeAttacher"
,
tmpDir
,
execScriptTempl1
,
nil
)
plugMgr
.
InitPlugins
(
ProbeVolumePlugins
(
tmpDir
),
volumetest
.
NewFakeVolumeHost
(
tmpDir
,
nil
,
nil
))
plugin
,
err
:=
plugMgr
.
FindPluginByName
(
"kubernetes.io/fakeAttacher"
)
if
err
!=
nil
{
t
.
Errorf
(
"Can't find the plugin by name"
)
}
fake
:=
&
mount
.
FakeMounter
{}
pod
:=
&
v1
.
Pod
{
ObjectMeta
:
metav1
.
ObjectMeta
{
UID
:
types
.
UID
(
"poduid"
)}}
secretMap
:=
make
(
map
[
string
]
string
)
secretMap
[
"flexsecret"
]
=
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
"foo"
))
mounter
,
err
:=
plugin
.
(
*
flexVolumePlugin
)
.
newMounterInternal
(
spec
,
pod
,
&
flexVolumeUtil
{},
fake
,
exec
.
New
(),
secretMap
)
volumePath
:=
mounter
.
GetPath
()
if
err
!=
nil
{
t
.
Errorf
(
"Failed to make a new Mounter: %v"
,
err
)
}
if
mounter
==
nil
{
t
.
Errorf
(
"Got a nil Mounter"
)
}
path
:=
mounter
.
GetPath
()
expectedPath
:=
fmt
.
Sprintf
(
"%s/pods/poduid/volumes/kubernetes.io~fakeAttacher/vol1"
,
tmpDir
)
if
path
!=
expectedPath
{
t
.
Errorf
(
"Unexpected path, expected %q, got: %q"
,
expectedPath
,
path
)
}
if
err
:=
mounter
.
SetUp
(
nil
);
err
!=
nil
{
t
.
Errorf
(
"Expected success, got: %v"
,
err
)
}
if
_
,
err
:=
os
.
Stat
(
volumePath
);
err
!=
nil
{
if
os
.
IsNotExist
(
err
)
{
t
.
Errorf
(
"SetUp() failed, volume path not created: %s"
,
volumePath
)
}
else
{
t
.
Errorf
(
"SetUp() failed: %v"
,
err
)
}
}
t
.
Logf
(
"Setup successful"
)
if
mounter
.
(
*
flexVolumeMounter
)
.
readOnly
{
t
.
Errorf
(
"The volume source should not be read-only and it is."
)
}
if
len
(
fake
.
Log
)
!=
1
{
t
.
Errorf
(
"Mount was not called exactly one time. It was called %d times."
,
len
(
fake
.
Log
))
}
else
{
if
fake
.
Log
[
0
]
.
Action
!=
mount
.
FakeActionMount
{
t
.
Errorf
(
"Unexpected mounter action: %#v"
,
fake
.
Log
[
0
])
}
}
fake
.
ResetLog
()
unmounter
,
err
:=
plugin
.
(
*
flexVolumePlugin
)
.
newUnmounterInternal
(
"vol1"
,
types
.
UID
(
"poduid"
),
&
flexVolumeUtil
{},
fake
,
exec
.
New
())
if
err
!=
nil
{
t
.
Errorf
(
"Failed to make a new Unmounter: %v"
,
err
)
}
if
unmounter
==
nil
{
t
.
Errorf
(
"Got a nil Unmounter"
)
}
if
err
:=
unmounter
.
TearDown
();
err
!=
nil
{
t
.
Errorf
(
"Expected success, got: %v"
,
err
)
}
if
_
,
err
:=
os
.
Stat
(
volumePath
);
err
==
nil
{
t
.
Errorf
(
"TearDown() failed, volume path still exists: %s"
,
volumePath
)
}
else
if
!
os
.
IsNotExist
(
err
)
{
t
.
Errorf
(
"SetUp() failed: %v"
,
err
)
}
if
len
(
fake
.
Log
)
!=
1
{
t
.
Errorf
(
"Unmount was not called exactly one time. It was called %d times."
,
len
(
fake
.
Log
))
}
else
{
if
fake
.
Log
[
0
]
.
Action
!=
mount
.
FakeActionUnmount
{
t
.
Errorf
(
"Unexpected mounter action: %#v"
,
fake
.
Log
[
0
])
}
}
fake
.
ResetLog
()
}
func
doTestPluginMountUnmount
(
t
*
testing
.
T
,
spec
*
volume
.
Spec
,
tmpDir
string
)
{
tmpDir
,
err
:=
utiltesting
.
MkTmpdir
(
"flexvolume_test"
)
if
err
!=
nil
{
t
.
Fatalf
(
"error creating temp dir: %v"
,
err
)
}
defer
os
.
RemoveAll
(
tmpDir
)
plugMgr
:=
volume
.
VolumePluginMgr
{}
installPluginUnderTest
(
t
,
"kubernetes.io"
,
"fakeMounter"
,
tmpDir
,
execScriptTempl2
,
nil
)
plugMgr
.
InitPlugins
(
ProbeVolumePlugins
(
tmpDir
),
volumetest
.
NewFakeVolumeHost
(
tmpDir
,
nil
,
nil
))
plugin
,
err
:=
plugMgr
.
FindPluginByName
(
"kubernetes.io/fakeMounter"
)
if
err
!=
nil
{
t
.
Errorf
(
"Can't find the plugin by name"
)
}
fake
:=
&
mount
.
FakeMounter
{}
pod
:=
&
v1
.
Pod
{
ObjectMeta
:
metav1
.
ObjectMeta
{
UID
:
types
.
UID
(
"poduid"
)}}
// Use nil secret to test for nil secret case.
mounter
,
err
:=
plugin
.
(
*
flexVolumePlugin
)
.
newMounterInternal
(
spec
,
pod
,
&
flexVolumeUtil
{},
fake
,
exec
.
New
(),
nil
)
volumePath
:=
mounter
.
GetPath
()
if
err
!=
nil
{
t
.
Errorf
(
"Failed to make a new Mounter: %v"
,
err
)
}
if
mounter
==
nil
{
t
.
Errorf
(
"Got a nil Mounter"
)
}
path
:=
mounter
.
GetPath
()
expectedPath
:=
fmt
.
Sprintf
(
"%s/pods/poduid/volumes/kubernetes.io~fakeMounter/vol1"
,
tmpDir
)
if
path
!=
expectedPath
{
t
.
Errorf
(
"Unexpected path, expected %q, got: %q"
,
expectedPath
,
path
)
}
if
err
:=
mounter
.
SetUp
(
nil
);
err
!=
nil
{
t
.
Errorf
(
"Expected success, got: %v"
,
err
)
}
if
_
,
err
:=
os
.
Stat
(
volumePath
);
err
!=
nil
{
if
os
.
IsNotExist
(
err
)
{
t
.
Errorf
(
"SetUp() failed, volume path not created: %s"
,
volumePath
)
}
else
{
t
.
Errorf
(
"SetUp() failed: %v"
,
err
)
}
}
t
.
Logf
(
"Setup successful"
)
if
mounter
.
(
*
flexVolumeMounter
)
.
readOnly
{
t
.
Errorf
(
"The volume source should not be read-only and it is."
)
}
unmounter
,
err
:=
plugin
.
(
*
flexVolumePlugin
)
.
newUnmounterInternal
(
"vol1"
,
types
.
UID
(
"poduid"
),
&
flexVolumeUtil
{},
fake
,
exec
.
New
())
if
err
!=
nil
{
t
.
Errorf
(
"Failed to make a new Unmounter: %v"
,
err
)
}
if
unmounter
==
nil
{
t
.
Errorf
(
"Got a nil Unmounter"
)
}
if
err
:=
unmounter
.
TearDown
();
err
!=
nil
{
t
.
Errorf
(
"Expected success, got: %v"
,
err
)
}
if
_
,
err
:=
os
.
Stat
(
volumePath
);
err
==
nil
{
t
.
Errorf
(
"TearDown() failed, volume path still exists: %s"
,
volumePath
)
}
else
if
!
os
.
IsNotExist
(
err
)
{
t
.
Errorf
(
"SetUp() failed: %v"
,
err
)
}
}
func
TestPluginVolumeAttacher
(
t
*
testing
.
T
)
{
tmpDir
,
err
:=
utiltesting
.
MkTmpdir
(
"flexvolume_test"
)
if
err
!=
nil
{
t
.
Fatalf
(
"error creating temp dir: %v"
,
err
)
}
defer
os
.
RemoveAll
(
tmpDir
)
vol
:=
&
v1
.
Volume
{
Name
:
"vol1"
,
VolumeSource
:
v1
.
VolumeSource
{
FlexVolume
:
&
v1
.
FlexVolumeSource
{
Driver
:
"kubernetes.io/fakeAttacher"
,
ReadOnly
:
false
}},
}
doTestPluginAttachDetach
(
t
,
volume
.
NewSpecFromVolume
(
vol
),
tmpDir
)
}
func
TestPluginVolumeMounter
(
t
*
testing
.
T
)
{
tmpDir
,
err
:=
utiltesting
.
MkTmpdir
(
"flexvolume_test"
)
if
err
!=
nil
{
t
.
Fatalf
(
"error creating temp dir: %v"
,
err
)
}
defer
os
.
RemoveAll
(
tmpDir
)
vol
:=
&
v1
.
Volume
{
Name
:
"vol1"
,
VolumeSource
:
v1
.
VolumeSource
{
FlexVolume
:
&
v1
.
FlexVolumeSource
{
Driver
:
"kubernetes.io/fakeMounter"
,
ReadOnly
:
false
}},
}
doTestPluginMountUnmount
(
t
,
volume
.
NewSpecFromVolume
(
vol
),
tmpDir
)
}
func
TestPluginPersistentVolume
(
t
*
testing
.
T
)
{
tmpDir
,
err
:=
utiltesting
.
MkTmpdir
(
"flexvolume_test"
)
if
err
!=
nil
{
t
.
Fatalf
(
"error creating temp dir: %v"
,
err
)
}
defer
os
.
RemoveAll
(
tmpDir
)
vol
:=
&
v1
.
PersistentVolume
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"vol1"
,
},
Spec
:
v1
.
PersistentVolumeSpec
{
PersistentVolumeSource
:
v1
.
PersistentVolumeSource
{
FlexVolume
:
&
v1
.
FlexVolumeSource
{
Driver
:
"kubernetes.io/fakeAttacher"
,
ReadOnly
:
false
},
},
},
}
doTestPluginAttachDetach
(
t
,
volume
.
NewSpecFromPersistentVolume
(
vol
,
false
),
tmpDir
)
}
pkg/volume/flexvolume/flexvolume_util.go
deleted
100644 → 0
View file @
46b20acb
/*
Copyright 2015 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
flexvolume
import
(
"encoding/json"
"errors"
"fmt"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/util/exec"
)
const
(
initCmd
=
"init"
attachCmd
=
"attach"
detachCmd
=
"detach"
mountCmd
=
"mount"
unmountCmd
=
"unmount"
optionFSType
=
"kubernetes.io/fsType"
optionReadWrite
=
"kubernetes.io/readwrite"
optionKeySecret
=
"kubernetes.io/secret"
)
const
(
// StatusSuccess represents the successful completion of command.
StatusSuccess
=
"Success"
// StatusFailed represents that the command failed.
StatusFailure
=
"Failed"
// StatusNotSupported represents that the command is not supported.
StatusNotSupported
=
"Not supported"
)
// FlexVolumeDriverStatus represents the return value of the driver callout.
type
FlexVolumeDriverStatus
struct
{
// Status of the callout. One of "Success" or "Failure".
Status
string
// Message is the reason for failure.
Message
string
// Device assigned by the driver.
Device
string
`json:"device"`
}
// flexVolumeUtil is the utility structure to setup and teardown devices from
// the host.
type
flexVolumeUtil
struct
{}
// isCmdNotSupportedErr checks if the error corresponds to command not supported by
// driver.
func
isCmdNotSupportedErr
(
err
error
)
bool
{
if
err
.
Error
()
==
StatusNotSupported
{
return
true
}
return
false
}
// handleCmdResponse processes the command output and returns the appropriate
// error code or message.
func
handleCmdResponse
(
cmd
string
,
output
[]
byte
)
(
*
FlexVolumeDriverStatus
,
error
)
{
var
status
FlexVolumeDriverStatus
if
err
:=
json
.
Unmarshal
(
output
,
&
status
);
err
!=
nil
{
glog
.
Errorf
(
"Failed to unmarshal output for command: %s, output: %s, error: %s"
,
cmd
,
output
,
err
.
Error
())
return
nil
,
err
}
else
if
status
.
Status
==
StatusNotSupported
{
glog
.
V
(
5
)
.
Infof
(
"%s command is not supported by the driver"
,
cmd
)
return
nil
,
errors
.
New
(
status
.
Status
)
}
else
if
status
.
Status
!=
StatusSuccess
{
errMsg
:=
fmt
.
Sprintf
(
"%s command failed, status: %s, reason: %s"
,
cmd
,
status
.
Status
,
status
.
Message
)
glog
.
Errorf
(
errMsg
)
return
nil
,
fmt
.
Errorf
(
"%s"
,
errMsg
)
}
return
&
status
,
nil
}
// init initializes the plugin.
func
(
u
*
flexVolumeUtil
)
init
(
plugin
*
flexVolumePlugin
)
error
{
// call the init script
output
,
err
:=
exec
.
New
()
.
Command
(
plugin
.
getExecutable
(),
initCmd
)
.
CombinedOutput
()
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to init driver: %s, error: %s"
,
plugin
.
driverName
,
err
.
Error
())
_
,
err
:=
handleCmdResponse
(
initCmd
,
output
)
return
err
}
glog
.
V
(
5
)
.
Infof
(
"Successfully initialized driver %s"
,
plugin
.
driverName
)
return
nil
}
// Attach exposes a volume on the host.
func
(
u
*
flexVolumeUtil
)
attach
(
f
*
flexVolumeMounter
)
(
string
,
error
)
{
execPath
:=
f
.
execPath
var
options
string
if
f
.
options
!=
nil
{
out
,
err
:=
json
.
Marshal
(
f
.
options
)
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to marshal plugin options, error: %s"
,
err
.
Error
())
return
""
,
err
}
if
len
(
out
)
!=
0
{
options
=
string
(
out
)
}
else
{
options
=
""
}
}
cmd
:=
f
.
runner
.
Command
(
execPath
,
attachCmd
,
options
)
output
,
err
:=
cmd
.
CombinedOutput
()
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to attach volume %s, output: %s, error: %s"
,
f
.
volName
,
output
,
err
.
Error
())
_
,
err
:=
handleCmdResponse
(
attachCmd
,
output
)
return
""
,
err
}
status
,
err
:=
handleCmdResponse
(
attachCmd
,
output
)
if
err
!=
nil
{
return
""
,
err
}
glog
.
Infof
(
"Successfully attached volume %s on device: %s"
,
f
.
volName
,
status
.
Device
)
return
status
.
Device
,
nil
}
// Detach detaches a volume from the host.
func
(
u
*
flexVolumeUtil
)
detach
(
f
*
flexVolumeUnmounter
,
mntDevice
string
)
error
{
execPath
:=
f
.
execPath
// Executable provider command.
cmd
:=
f
.
runner
.
Command
(
execPath
,
detachCmd
,
mntDevice
)
output
,
err
:=
cmd
.
CombinedOutput
()
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to detach volume %s, output: %s, error: %s"
,
f
.
volName
,
output
,
err
.
Error
())
_
,
err
:=
handleCmdResponse
(
detachCmd
,
output
)
return
err
}
_
,
err
=
handleCmdResponse
(
detachCmd
,
output
)
if
err
!=
nil
{
return
err
}
glog
.
Infof
(
"Successfully detached volume %s on device: %s"
,
f
.
volName
,
mntDevice
)
return
nil
}
// Mount mounts the volume on the host.
func
(
u
*
flexVolumeUtil
)
mount
(
f
*
flexVolumeMounter
,
mntDevice
,
dir
string
)
error
{
execPath
:=
f
.
execPath
var
options
string
if
f
.
options
!=
nil
{
out
,
err
:=
json
.
Marshal
(
f
.
options
)
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to marshal plugin options, error: %s"
,
err
.
Error
())
return
err
}
if
len
(
out
)
!=
0
{
options
=
string
(
out
)
}
else
{
options
=
""
}
}
// Executable provider command.
cmd
:=
f
.
runner
.
Command
(
execPath
,
mountCmd
,
dir
,
mntDevice
,
options
)
output
,
err
:=
cmd
.
CombinedOutput
()
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to mount volume %s, output: %s, error: %s"
,
f
.
volName
,
output
,
err
.
Error
())
_
,
err
:=
handleCmdResponse
(
mountCmd
,
output
)
return
err
}
_
,
err
=
handleCmdResponse
(
mountCmd
,
output
)
if
err
!=
nil
{
return
err
}
glog
.
Infof
(
"Successfully mounted volume %s on dir: %s"
,
f
.
volName
,
dir
)
return
nil
}
// Unmount unmounts the volume on the host.
func
(
u
*
flexVolumeUtil
)
unmount
(
f
*
flexVolumeUnmounter
,
dir
string
)
error
{
execPath
:=
f
.
execPath
// Executable provider command.
cmd
:=
f
.
runner
.
Command
(
execPath
,
unmountCmd
,
dir
)
output
,
err
:=
cmd
.
CombinedOutput
()
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to unmount volume %s, output: %s, error: %s"
,
f
.
volName
,
output
,
err
.
Error
())
_
,
err
:=
handleCmdResponse
(
unmountCmd
,
output
)
return
err
}
_
,
err
=
handleCmdResponse
(
unmountCmd
,
output
)
if
err
!=
nil
{
return
err
}
glog
.
Infof
(
"Successfully unmounted volume %s on dir: %s"
,
f
.
volName
,
dir
)
return
nil
}
pkg/volume/flexvolume/mounter-defaults.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"fmt"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/volume"
)
type
mounterDefaults
flexVolumeMounter
// SetUpAt is part of the volume.Mounter interface.
// This implementation relies on the attacher's device mount path and does a bind mount to dir.
func
(
f
*
mounterDefaults
)
SetUpAt
(
dir
string
,
fsGroup
*
int64
)
error
{
glog
.
Warning
(
logPrefix
(
f
.
plugin
),
"using default SetUpAt to "
,
dir
)
a
,
err
:=
f
.
plugin
.
NewAttacher
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"NewAttacher failed: %v"
,
err
)
}
src
,
err
:=
a
.
GetDeviceMountPath
(
f
.
spec
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"GetDeviceMountPath failed: %v"
,
err
)
}
if
err
:=
doMount
(
f
.
mounter
,
src
,
dir
,
"auto"
,
[]
string
{
"bind"
});
err
!=
nil
{
return
err
}
return
nil
}
// Returns the default volume attributes.
func
(
f
*
mounterDefaults
)
GetAttributes
()
volume
.
Attributes
{
glog
.
V
(
5
)
.
Infof
(
logPrefix
(
f
.
plugin
),
"using default GetAttributes"
)
return
volume
.
Attributes
{
ReadOnly
:
f
.
readOnly
,
Managed
:
!
f
.
readOnly
,
SupportsSELinux
:
true
,
}
}
func
(
f
*
mounterDefaults
)
CanMount
()
error
{
return
nil
}
pkg/volume/flexvolume/mounter.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"strconv"
"k8s.io/kubernetes/pkg/util/exec"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
)
// FlexVolumeMounter is the disk that will be exposed by this plugin.
type
flexVolumeMounter
struct
{
*
flexVolume
// Runner used to setup the volume.
runner
exec
.
Interface
// blockDeviceMounter provides the interface to create filesystem if the
// filesystem doesn't exist.
blockDeviceMounter
mount
.
Interface
// the considered volume spec
spec
*
volume
.
Spec
readOnly
bool
volume
.
MetricsNil
}
var
_
volume
.
Mounter
=
&
flexVolumeMounter
{}
// Mounter interface
// SetUp creates new directory.
func
(
f
*
flexVolumeMounter
)
SetUp
(
fsGroup
*
int64
)
error
{
return
f
.
SetUpAt
(
f
.
GetPath
(),
fsGroup
)
}
// SetUpAt creates new directory.
func
(
f
*
flexVolumeMounter
)
SetUpAt
(
dir
string
,
fsGroup
*
int64
)
error
{
// Mount only once.
alreadyMounted
,
err
:=
prepareForMount
(
f
.
mounter
,
dir
)
if
err
!=
nil
{
return
err
}
if
alreadyMounted
{
return
nil
}
call
:=
f
.
plugin
.
NewDriverCall
(
mountCmd
)
// Interface parameters
call
.
Append
(
dir
)
extraOptions
:=
make
(
map
[
string
]
string
)
// Extract secret and pass it as options.
if
err
:=
addSecretsToOptions
(
extraOptions
,
f
.
spec
,
f
.
podNamespace
,
f
.
driverName
,
f
.
plugin
.
host
);
err
!=
nil
{
return
err
}
// Implicit parameters
if
fsGroup
!=
nil
{
extraOptions
[
optionFSGroup
]
=
strconv
.
FormatInt
(
*
fsGroup
,
10
)
}
call
.
AppendSpec
(
f
.
spec
,
f
.
plugin
.
host
,
extraOptions
)
_
,
err
=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
err
=
(
*
mounterDefaults
)(
f
)
.
SetUpAt
(
dir
,
fsGroup
)
}
if
err
!=
nil
{
return
err
}
if
!
f
.
readOnly
{
volume
.
SetVolumeOwnership
(
f
,
fsGroup
)
}
return
nil
}
// GetAttributes get the flex volume attributes. The attributes will be queried
// using plugin callout after we finalize the callout syntax.
func
(
f
*
flexVolumeMounter
)
GetAttributes
()
volume
.
Attributes
{
return
(
*
mounterDefaults
)(
f
)
.
GetAttributes
()
}
func
(
f
*
flexVolumeMounter
)
CanMount
()
error
{
return
nil
}
pkg/volume/flexvolume/mounter_test.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"testing"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/util/mount"
)
func
TestSetUpAt
(
t
*
testing
.
T
)
{
spec
:=
fakeVolumeSpec
()
pod
:=
&
v1
.
Pod
{}
mounter
:=
&
mount
.
FakeMounter
{}
plugin
,
rootDir
:=
testPlugin
()
plugin
.
unsupportedCommands
=
[]
string
{
"unsupportedCmd"
}
plugin
.
runner
=
fakeRunner
(
// first call without fsGroup
assertDriverCall
(
t
,
successOutput
(),
mountCmd
,
rootDir
+
"/mount-dir"
,
specJson
(
plugin
,
spec
,
nil
)),
// second test has fsGroup
assertDriverCall
(
t
,
notSupportedOutput
(),
mountCmd
,
rootDir
+
"/mount-dir"
,
specJson
(
plugin
,
spec
,
map
[
string
]
string
{
optionFSGroup
:
"42"
,
})),
assertDriverCall
(
t
,
fakeVolumeNameOutput
(
"sdx"
),
getVolumeNameCmd
,
specJson
(
plugin
,
spec
,
nil
)),
)
m
,
_
:=
plugin
.
newMounterInternal
(
spec
,
pod
,
mounter
,
plugin
.
runner
)
m
.
SetUpAt
(
rootDir
+
"/mount-dir"
,
nil
)
fsGroup
:=
int64
(
42
)
m
.
SetUpAt
(
rootDir
+
"/mount-dir"
,
&
fsGroup
)
}
pkg/volume/flexvolume/plugin-defaults.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/volume"
)
type
pluginDefaults
flexVolumePlugin
func
logPrefix
(
plugin
*
flexVolumePlugin
)
string
{
return
"flexVolume driver "
+
plugin
.
driverName
+
": "
}
func
(
plugin
*
pluginDefaults
)
GetVolumeName
(
spec
*
volume
.
Spec
)
(
string
,
error
)
{
glog
.
Warning
(
logPrefix
((
*
flexVolumePlugin
)(
plugin
)),
"using default GetVolumeName for volume "
,
spec
.
Name
)
return
spec
.
Name
(),
nil
}
pkg/volume/flexvolume/plugin.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"path"
"strings"
"sync"
"k8s.io/apimachinery/pkg/types"
api
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/util/exec"
"k8s.io/kubernetes/pkg/util/mount"
utilstrings
"k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
)
const
flexVolumePluginName
=
"kubernetes.io/flexvolume"
// FlexVolumePlugin object.
type
flexVolumePlugin
struct
{
driverName
string
execPath
string
host
volume
.
VolumeHost
runner
exec
.
Interface
sync
.
Mutex
unsupportedCommands
[]
string
}
var
_
volume
.
AttachableVolumePlugin
=
&
flexVolumePlugin
{}
var
_
volume
.
PersistentVolumePlugin
=
&
flexVolumePlugin
{}
// Init is part of the volume.VolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
Init
(
host
volume
.
VolumeHost
)
error
{
plugin
.
host
=
host
// call the init script
call
:=
plugin
.
NewDriverCall
(
initCmd
)
_
,
err
:=
call
.
Run
()
return
err
}
func
(
plugin
*
flexVolumePlugin
)
getExecutable
()
string
{
parts
:=
strings
.
Split
(
plugin
.
driverName
,
"/"
)
execName
:=
parts
[
len
(
parts
)
-
1
]
return
path
.
Join
(
plugin
.
execPath
,
execName
)
}
// Name is part of the volume.VolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
GetPluginName
()
string
{
return
plugin
.
driverName
}
// GetVolumeName is part of the volume.VolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
GetVolumeName
(
spec
*
volume
.
Spec
)
(
string
,
error
)
{
call
:=
plugin
.
NewDriverCall
(
getVolumeNameCmd
)
call
.
AppendSpec
(
spec
,
plugin
.
host
,
nil
)
status
,
err
:=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
return
(
*
pluginDefaults
)(
plugin
)
.
GetVolumeName
(
spec
)
}
else
if
err
!=
nil
{
return
""
,
err
}
return
utilstrings
.
EscapeQualifiedNameForDisk
(
status
.
VolumeName
),
nil
}
// CanSupport is part of the volume.VolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
CanSupport
(
spec
*
volume
.
Spec
)
bool
{
source
,
_
:=
getVolumeSource
(
spec
)
return
(
source
!=
nil
)
&&
(
source
.
Driver
==
plugin
.
driverName
)
}
// RequiresRemount is part of the volume.VolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
RequiresRemount
()
bool
{
return
false
}
// GetAccessModes gets the allowed access modes for this plugin.
func
(
plugin
*
flexVolumePlugin
)
GetAccessModes
()
[]
api
.
PersistentVolumeAccessMode
{
return
[]
api
.
PersistentVolumeAccessMode
{
api
.
ReadWriteOnce
,
api
.
ReadOnlyMany
,
}
}
// NewMounter is part of the volume.VolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
NewMounter
(
spec
*
volume
.
Spec
,
pod
*
api
.
Pod
,
_
volume
.
VolumeOptions
)
(
volume
.
Mounter
,
error
)
{
return
plugin
.
newMounterInternal
(
spec
,
pod
,
plugin
.
host
.
GetMounter
(),
plugin
.
runner
)
}
// newMounterInternal is the internal mounter routine to build the volume.
func
(
plugin
*
flexVolumePlugin
)
newMounterInternal
(
spec
*
volume
.
Spec
,
pod
*
api
.
Pod
,
mounter
mount
.
Interface
,
runner
exec
.
Interface
)
(
volume
.
Mounter
,
error
)
{
source
,
readOnly
:=
getVolumeSource
(
spec
)
return
&
flexVolumeMounter
{
flexVolume
:
&
flexVolume
{
driverName
:
source
.
Driver
,
execPath
:
plugin
.
getExecutable
(),
mounter
:
mounter
,
plugin
:
plugin
,
podUID
:
pod
.
UID
,
podNamespace
:
pod
.
Namespace
,
volName
:
spec
.
Name
(),
},
runner
:
runner
,
spec
:
spec
,
readOnly
:
readOnly
,
blockDeviceMounter
:
&
mount
.
SafeFormatAndMount
{
Interface
:
mounter
,
Runner
:
runner
},
},
nil
}
// NewUnmounter is part of the volume.VolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
NewUnmounter
(
volName
string
,
podUID
types
.
UID
)
(
volume
.
Unmounter
,
error
)
{
return
plugin
.
newUnmounterInternal
(
volName
,
podUID
,
plugin
.
host
.
GetMounter
(),
plugin
.
runner
)
}
// newUnmounterInternal is the internal unmounter routine to clean the volume.
func
(
plugin
*
flexVolumePlugin
)
newUnmounterInternal
(
volName
string
,
podUID
types
.
UID
,
mounter
mount
.
Interface
,
runner
exec
.
Interface
)
(
volume
.
Unmounter
,
error
)
{
return
&
flexVolumeUnmounter
{
flexVolume
:
&
flexVolume
{
driverName
:
plugin
.
driverName
,
execPath
:
plugin
.
getExecutable
(),
mounter
:
mounter
,
plugin
:
plugin
,
podUID
:
podUID
,
volName
:
volName
,
},
runner
:
runner
,
},
nil
}
// NewAttacher is part of the volume.AttachableVolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
NewAttacher
()
(
volume
.
Attacher
,
error
)
{
return
&
flexVolumeAttacher
{
plugin
},
nil
}
// NewDetacher is part of the volume.AttachableVolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
NewDetacher
()
(
volume
.
Detacher
,
error
)
{
return
&
flexVolumeDetacher
{
plugin
},
nil
}
// ConstructVolumeSpec is part of the volume.AttachableVolumePlugin interface.
func
(
plugin
*
flexVolumePlugin
)
ConstructVolumeSpec
(
volumeName
,
mountPath
string
)
(
*
volume
.
Spec
,
error
)
{
flexVolume
:=
&
api
.
Volume
{
Name
:
volumeName
,
VolumeSource
:
api
.
VolumeSource
{
FlexVolume
:
&
api
.
FlexVolumeSource
{
Driver
:
plugin
.
driverName
,
},
},
}
return
volume
.
NewSpecFromVolume
(
flexVolume
),
nil
}
// Mark the given commands as unsupported.
func
(
plugin
*
flexVolumePlugin
)
unsupported
(
commands
...
string
)
{
plugin
.
Lock
()
defer
plugin
.
Unlock
()
plugin
.
unsupportedCommands
=
append
(
plugin
.
unsupportedCommands
,
commands
...
)
}
// Returns true iff the given command is known to be unsupported.
func
(
plugin
*
flexVolumePlugin
)
isUnsupported
(
command
string
)
bool
{
plugin
.
Lock
()
defer
plugin
.
Unlock
()
for
_
,
unsupportedCommand
:=
range
plugin
.
unsupportedCommands
{
if
command
==
unsupportedCommand
{
return
true
}
}
return
false
}
func
(
plugin
*
flexVolumePlugin
)
GetDeviceMountRefs
(
deviceMountPath
string
)
([]
string
,
error
)
{
mounter
:=
plugin
.
host
.
GetMounter
()
return
mount
.
GetMountRefs
(
mounter
,
deviceMountPath
)
}
pkg/volume/flexvolume/plugin_test.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"testing"
"k8s.io/kubernetes/pkg/util/exec"
)
func
TestInit
(
t
*
testing
.
T
)
{
plugin
,
_
:=
testPlugin
()
plugin
.
runner
=
fakeRunner
(
assertDriverCall
(
t
,
successOutput
(),
"init"
),
)
plugin
.
Init
(
plugin
.
host
)
}
func
fakeVolumeNameOutput
(
name
string
)
exec
.
FakeCombinedOutputAction
{
return
fakeResultOutput
(
&
DriverStatus
{
Status
:
StatusSuccess
,
VolumeName
:
name
,
})
}
func
TestGetVolumeName
(
t
*
testing
.
T
)
{
spec
:=
fakeVolumeSpec
()
plugin
,
_
:=
testPlugin
()
plugin
.
runner
=
fakeRunner
(
assertDriverCall
(
t
,
fakeVolumeNameOutput
(
"/dev/sdx"
),
getVolumeNameCmd
,
specJson
(
plugin
,
spec
,
nil
)),
)
name
,
err
:=
plugin
.
GetVolumeName
(
spec
)
if
err
!=
nil
{
t
.
Errorf
(
"GetVolumeName() failed: %v"
,
err
)
}
expectedName
:=
"~dev~sdx"
if
name
!=
expectedName
{
t
.
Errorf
(
"GetVolumeName() returned %v instead of %v"
,
name
,
expectedName
)
}
}
pkg/volume/flexvolume/probe.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"io/ioutil"
"path"
"k8s.io/kubernetes/pkg/util/exec"
utilstrings
"k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
)
// This is the primary entrypoint for volume plugins.
func
ProbeVolumePlugins
(
pluginDir
string
)
[]
volume
.
VolumePlugin
{
plugins
:=
[]
volume
.
VolumePlugin
{}
files
,
_
:=
ioutil
.
ReadDir
(
pluginDir
)
for
_
,
f
:=
range
files
{
// only directories are counted as plugins
// and pluginDir/dirname/dirname should be an executable
// unless dirname contains '~' for escaping namespace
// e.g. dirname = vendor~cifs
// then, executable will be pluginDir/dirname/cifs
if
f
.
IsDir
()
{
execPath
:=
path
.
Join
(
pluginDir
,
f
.
Name
())
plugins
=
append
(
plugins
,
&
flexVolumePlugin
{
driverName
:
utilstrings
.
UnescapePluginName
(
f
.
Name
()),
execPath
:
execPath
,
runner
:
exec
.
New
(),
unsupportedCommands
:
[]
string
{},
})
}
}
return
plugins
}
pkg/volume/flexvolume/unmounter-defaults.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/volume/util"
)
type
unmounterDefaults
flexVolumeUnmounter
func
(
f
*
unmounterDefaults
)
TearDownAt
(
dir
string
)
error
{
glog
.
Warning
(
logPrefix
(
f
.
plugin
),
"using default TearDownAt for "
,
dir
)
return
util
.
UnmountPath
(
dir
,
f
.
mounter
)
}
pkg/volume/flexvolume/unmounter.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"fmt"
"os"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/util/exec"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
)
// FlexVolumeUnmounter is the disk that will be cleaned by this plugin.
type
flexVolumeUnmounter
struct
{
*
flexVolume
// Runner used to teardown the volume.
runner
exec
.
Interface
volume
.
MetricsNil
}
var
_
volume
.
Unmounter
=
&
flexVolumeUnmounter
{}
// Unmounter interface
func
(
f
*
flexVolumeUnmounter
)
TearDown
()
error
{
path
:=
f
.
GetPath
()
return
f
.
TearDownAt
(
path
)
}
func
(
f
*
flexVolumeUnmounter
)
TearDownAt
(
dir
string
)
error
{
if
pathExists
,
pathErr
:=
util
.
PathExists
(
dir
);
pathErr
!=
nil
{
return
fmt
.
Errorf
(
"Error checking if path exists: %v"
,
pathErr
)
}
else
if
!
pathExists
{
glog
.
Warningf
(
"Warning: Unmount skipped because path does not exist: %v"
,
dir
)
return
nil
}
notmnt
,
err
:=
isNotMounted
(
f
.
mounter
,
dir
)
if
err
!=
nil
{
return
err
}
if
notmnt
{
glog
.
Warningf
(
"Warning: Path: %v already unmounted"
,
dir
)
}
else
{
call
:=
f
.
plugin
.
NewDriverCall
(
unmountCmd
)
call
.
Append
(
dir
)
_
,
err
:=
call
.
Run
()
if
isCmdNotSupportedErr
(
err
)
{
err
=
(
*
unmounterDefaults
)(
f
)
.
TearDownAt
(
dir
)
}
if
err
!=
nil
{
return
err
}
}
// Flexvolume driver may remove the directory. Ignore if it does.
if
pathExists
,
pathErr
:=
util
.
PathExists
(
dir
);
pathErr
!=
nil
{
return
fmt
.
Errorf
(
"Error checking if path exists: %v"
,
pathErr
)
}
else
if
!
pathExists
{
return
nil
}
return
os
.
Remove
(
dir
)
}
pkg/volume/flexvolume/unmounter_test.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"testing"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/util/mount"
)
func
TestTearDownAt
(
t
*
testing
.
T
)
{
mounter
:=
&
mount
.
FakeMounter
{}
plugin
,
rootDir
:=
testPlugin
()
plugin
.
runner
=
fakeRunner
(
assertDriverCall
(
t
,
notSupportedOutput
(),
unmountCmd
,
rootDir
+
"/mount-dir"
),
)
u
,
_
:=
plugin
.
newUnmounterInternal
(
"volName"
,
types
.
UID
(
"poduid"
),
mounter
,
plugin
.
runner
)
u
.
TearDownAt
(
rootDir
+
"/mount-dir"
)
}
pkg/volume/flexvolume/util.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"encoding/base64"
"fmt"
"os"
"github.com/golang/glog"
api
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
)
func
addSecretsToOptions
(
options
map
[
string
]
string
,
spec
*
volume
.
Spec
,
namespace
string
,
driverName
string
,
host
volume
.
VolumeHost
)
error
{
fv
,
_
:=
getVolumeSource
(
spec
)
if
fv
.
SecretRef
==
nil
{
return
nil
}
kubeClient
:=
host
.
GetKubeClient
()
if
kubeClient
==
nil
{
return
fmt
.
Errorf
(
"Cannot get kube client"
)
}
secrets
,
err
:=
util
.
GetSecretForPV
(
namespace
,
fv
.
SecretRef
.
Name
,
driverName
,
host
.
GetKubeClient
())
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Couldn't get secret %v/%v err: %v"
,
namespace
,
fv
.
SecretRef
.
Name
,
err
)
return
err
}
for
name
,
data
:=
range
secrets
{
options
[
optionKeySecret
+
"/"
+
name
]
=
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
data
))
glog
.
V
(
1
)
.
Infof
(
"found flex volume secret info: %s"
,
name
)
}
return
nil
}
func
getVolumeSource
(
spec
*
volume
.
Spec
)
(
volumeSource
*
api
.
FlexVolumeSource
,
readOnly
bool
)
{
if
spec
.
Volume
!=
nil
&&
spec
.
Volume
.
FlexVolume
!=
nil
{
volumeSource
=
spec
.
Volume
.
FlexVolume
readOnly
=
volumeSource
.
ReadOnly
}
else
if
spec
.
PersistentVolume
!=
nil
{
volumeSource
=
spec
.
PersistentVolume
.
Spec
.
FlexVolume
readOnly
=
spec
.
ReadOnly
}
return
}
func
prepareForMount
(
mounter
mount
.
Interface
,
deviceMountPath
string
)
(
bool
,
error
)
{
notMnt
,
err
:=
mounter
.
IsLikelyNotMountPoint
(
deviceMountPath
)
if
err
!=
nil
{
if
os
.
IsNotExist
(
err
)
{
if
err
:=
os
.
MkdirAll
(
deviceMountPath
,
0750
);
err
!=
nil
{
return
false
,
err
}
notMnt
=
true
}
else
{
return
false
,
err
}
}
return
!
notMnt
,
nil
}
// Mounts the device at the given path.
// It is expected that prepareForMount has been called before.
func
doMount
(
mounter
mount
.
Interface
,
devicePath
,
deviceMountPath
,
fsType
string
,
options
[]
string
)
error
{
err
:=
mounter
.
Mount
(
devicePath
,
deviceMountPath
,
fsType
,
options
)
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to mount the volume at %s, device: %s, error: %s"
,
deviceMountPath
,
devicePath
,
err
.
Error
())
return
err
}
return
nil
}
func
isNotMounted
(
mounter
mount
.
Interface
,
deviceMountPath
string
)
(
bool
,
error
)
{
notmnt
,
err
:=
mounter
.
IsLikelyNotMountPoint
(
deviceMountPath
)
if
err
!=
nil
{
glog
.
Errorf
(
"Error checking mount point %s, error: %v"
,
deviceMountPath
,
err
)
return
false
,
err
}
return
notmnt
,
nil
}
pkg/volume/flexvolume/volume.go
0 → 100644
View file @
0d2af70e
/*
Copyright 2017 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
flexvolume
import
(
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/util/mount"
utilstrings
"k8s.io/kubernetes/pkg/util/strings"
)
type
flexVolume
struct
{
// driverName is the name of the plugin driverName.
driverName
string
// Driver executable used to setup the volume.
execPath
string
// mounter provides the interface that is used to mount the actual
// block device.
mounter
mount
.
Interface
// podUID is the UID of the pod.
podUID
types
.
UID
// podNamespace is the namespace of the pod.
podNamespace
string
// volName is the name of the pod's volume.
volName
string
// the underlying plugin
plugin
*
flexVolumePlugin
}
// volume.Volume interface
func
(
f
*
flexVolume
)
GetPath
()
string
{
name
:=
f
.
driverName
return
f
.
plugin
.
host
.
GetPodVolumeDir
(
f
.
podUID
,
utilstrings
.
EscapeQualifiedNameForDisk
(
name
),
f
.
volName
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment