2015-03-26 18:53:21 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2015-03-26 18:53:21 +00:00
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 glusterfs
import (
2015-10-07 16:47:11 +00:00
"fmt"
2016-09-20 14:24:30 +00:00
"os"
"path"
dstrings "strings"
2015-08-05 22:05:17 +00:00
"github.com/golang/glog"
2016-08-19 15:25:39 +00:00
gcli "github.com/heketi/heketi/client/api/go-client"
gapi "github.com/heketi/heketi/pkg/glusterfs/api"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
2016-08-19 15:25:39 +00:00
"k8s.io/kubernetes/pkg/api/resource"
2016-09-20 14:24:30 +00:00
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/exec"
"k8s.io/kubernetes/pkg/util/mount"
2016-01-11 07:55:51 +00:00
"k8s.io/kubernetes/pkg/util/strings"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/volume"
2016-09-20 14:24:30 +00:00
volutil "k8s.io/kubernetes/pkg/volume/util"
2015-03-26 18:53:21 +00:00
)
// This is the primary entrypoint for volume plugins.
func ProbeVolumePlugins ( ) [ ] volume . VolumePlugin {
2016-09-20 14:24:30 +00:00
return [ ] volume . VolumePlugin { & glusterfsPlugin { nil , exec . New ( ) } }
2015-03-26 18:53:21 +00:00
}
type glusterfsPlugin struct {
2016-09-20 14:24:30 +00:00
host volume . VolumeHost
exe exec . Interface
2015-03-26 18:53:21 +00:00
}
var _ volume . VolumePlugin = & glusterfsPlugin { }
2015-06-26 20:37:11 +00:00
var _ volume . PersistentVolumePlugin = & glusterfsPlugin { }
2016-08-19 15:25:39 +00:00
var _ volume . DeletableVolumePlugin = & glusterfsPlugin { }
var _ volume . ProvisionableVolumePlugin = & glusterfsPlugin { }
var _ volume . Provisioner = & glusterfsVolumeProvisioner { }
var _ volume . Deleter = & glusterfsVolumeDeleter { }
2015-03-26 18:53:21 +00:00
const (
2016-09-20 14:24:30 +00:00
glusterfsPluginName = "kubernetes.io/glusterfs"
volprefix = "vol_"
replicacount = 3
durabilitytype = "replicate"
secretKeyName = "key" // key name used in secret
annGlusterURL = "glusterfs.kubernetes.io/url"
annGlusterSecretName = "glusterfs.kubernetes.io/secretname"
annGlusterSecretNamespace = "glusterfs.kubernetes.io/secretnamespace"
annGlusterUserKey = "glusterfs.kubernetes.io/userkey"
annGlusterUser = "glusterfs.kubernetes.io/userid"
2015-03-26 18:53:21 +00:00
)
2015-09-30 18:31:53 +00:00
func ( plugin * glusterfsPlugin ) Init ( host volume . VolumeHost ) error {
2015-03-26 18:53:21 +00:00
plugin . host = host
2015-09-30 18:31:53 +00:00
return nil
2015-03-26 18:53:21 +00:00
}
2016-05-30 22:48:21 +00:00
func ( plugin * glusterfsPlugin ) GetPluginName ( ) string {
2015-03-26 18:53:21 +00:00
return glusterfsPluginName
}
2016-05-30 22:48:21 +00:00
func ( plugin * glusterfsPlugin ) GetVolumeName ( spec * volume . Spec ) ( string , error ) {
2016-05-30 02:22:22 +00:00
volumeSource , _ , err := getVolumeSource ( spec )
if err != nil {
return "" , err
2016-05-30 22:48:21 +00:00
}
return fmt . Sprintf (
"%v:%v" ,
volumeSource . EndpointsName ,
volumeSource . Path ) , nil
}
2015-04-14 16:29:33 +00:00
func ( plugin * glusterfsPlugin ) CanSupport ( spec * volume . Spec ) bool {
2015-10-07 16:47:11 +00:00
if ( spec . PersistentVolume != nil && spec . PersistentVolume . Spec . Glusterfs == nil ) ||
( spec . Volume != nil && spec . Volume . Glusterfs == nil ) {
return false
}
2016-02-25 19:00:12 +00:00
2016-02-23 15:40:35 +00:00
return true
2016-05-30 02:22:22 +00:00
}
2015-10-07 16:47:11 +00:00
2016-05-30 02:22:22 +00:00
func ( plugin * glusterfsPlugin ) RequiresRemount ( ) bool {
return false
2015-03-26 18:53:21 +00:00
}
2015-05-18 20:22:30 +00:00
func ( plugin * glusterfsPlugin ) GetAccessModes ( ) [ ] api . PersistentVolumeAccessMode {
return [ ] api . PersistentVolumeAccessMode {
2015-03-26 18:53:21 +00:00
api . ReadWriteOnce ,
api . ReadOnlyMany ,
api . ReadWriteMany ,
}
}
2016-03-23 05:12:21 +00:00
func ( plugin * glusterfsPlugin ) NewMounter ( spec * volume . Spec , pod * api . Pod , _ volume . VolumeOptions ) ( volume . Mounter , error ) {
2015-06-26 20:37:11 +00:00
source , _ := plugin . getGlusterVolumeSource ( spec )
2015-06-01 14:34:40 +00:00
ep_name := source . EndpointsName
2015-05-11 00:12:57 +00:00
ns := pod . Namespace
2016-02-03 21:21:05 +00:00
ep , err := plugin . host . GetKubeClient ( ) . Core ( ) . Endpoints ( ns ) . Get ( ep_name )
2015-03-26 18:53:21 +00:00
if err != nil {
2015-10-07 16:47:11 +00:00
glog . Errorf ( "glusterfs: failed to get endpoints %s[%v]" , ep_name , err )
2015-03-26 18:53:21 +00:00
return nil , err
}
2015-10-07 16:47:11 +00:00
glog . V ( 1 ) . Infof ( "glusterfs: endpoints %v" , ep )
2016-03-23 05:12:21 +00:00
return plugin . newMounterInternal ( spec , ep , pod , plugin . host . GetMounter ( ) , exec . New ( ) )
2015-03-26 18:53:21 +00:00
}
2015-06-26 20:37:11 +00:00
func ( plugin * glusterfsPlugin ) getGlusterVolumeSource ( spec * volume . Spec ) ( * api . GlusterfsVolumeSource , bool ) {
// Glusterfs volumes used directly in a pod have a ReadOnly flag set by the pod author.
// Glusterfs volumes used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
2015-08-12 19:11:03 +00:00
if spec . Volume != nil && spec . Volume . Glusterfs != nil {
return spec . Volume . Glusterfs , spec . Volume . Glusterfs . ReadOnly
2015-06-01 14:34:40 +00:00
} else {
2015-08-12 19:11:03 +00:00
return spec . PersistentVolume . Spec . Glusterfs , spec . ReadOnly
2015-06-01 14:34:40 +00:00
}
}
2016-03-23 05:12:21 +00:00
func ( plugin * glusterfsPlugin ) newMounterInternal ( spec * volume . Spec , ep * api . Endpoints , pod * api . Pod , mounter mount . Interface , exe exec . Interface ) ( volume . Mounter , error ) {
2015-06-26 20:37:11 +00:00
source , readOnly := plugin . getGlusterVolumeSource ( spec )
2016-03-23 05:12:21 +00:00
return & glusterfsMounter {
2015-07-23 07:07:40 +00:00
glusterfs : & glusterfs {
2015-08-12 19:11:03 +00:00
volName : spec . Name ( ) ,
2015-07-23 07:07:40 +00:00
mounter : mounter ,
pod : pod ,
plugin : plugin ,
} ,
2015-03-26 18:53:21 +00:00
hosts : ep ,
2015-06-01 14:34:40 +00:00
path : source . Path ,
2015-06-29 16:54:43 +00:00
readOnly : readOnly ,
2015-07-23 07:07:40 +00:00
exe : exe } , nil
2015-03-26 18:53:21 +00:00
}
2016-03-23 05:12:21 +00:00
func ( plugin * glusterfsPlugin ) NewUnmounter ( volName string , podUID types . UID ) ( volume . Unmounter , error ) {
return plugin . newUnmounterInternal ( volName , podUID , plugin . host . GetMounter ( ) )
2015-03-26 18:53:21 +00:00
}
2016-03-23 05:12:21 +00:00
func ( plugin * glusterfsPlugin ) newUnmounterInternal ( volName string , podUID types . UID , mounter mount . Interface ) ( volume . Unmounter , error ) {
return & glusterfsUnmounter { & glusterfs {
2015-03-26 18:53:21 +00:00
volName : volName ,
mounter : mounter ,
2015-05-11 00:12:57 +00:00
pod : & api . Pod { ObjectMeta : api . ObjectMeta { UID : podUID } } ,
2015-03-26 18:53:21 +00:00
plugin : plugin ,
2015-07-23 07:07:40 +00:00
} } , nil
2015-03-26 18:53:21 +00:00
}
2015-10-07 16:47:11 +00:00
func ( plugin * glusterfsPlugin ) execCommand ( command string , args [ ] string ) ( [ ] byte , error ) {
cmd := plugin . exe . Command ( command , args ... )
return cmd . CombinedOutput ( )
}
2016-06-23 19:46:21 +00:00
func ( plugin * glusterfsPlugin ) ConstructVolumeSpec ( volumeName , mountPath string ) ( * volume . Spec , error ) {
glusterfsVolume := & api . Volume {
Name : volumeName ,
VolumeSource : api . VolumeSource {
Glusterfs : & api . GlusterfsVolumeSource {
EndpointsName : volumeName ,
Path : volumeName ,
} ,
} ,
}
return volume . NewSpecFromVolume ( glusterfsVolume ) , nil
}
2015-03-26 18:53:21 +00:00
// Glusterfs volumes represent a bare host file or directory mount of an Glusterfs export.
type glusterfs struct {
2015-07-23 07:07:40 +00:00
volName string
pod * api . Pod
mounter mount . Interface
plugin * glusterfsPlugin
2015-12-04 20:40:01 +00:00
volume . MetricsNil
2015-07-23 07:07:40 +00:00
}
2016-03-23 05:12:21 +00:00
type glusterfsMounter struct {
2015-07-23 07:07:40 +00:00
* glusterfs
2015-03-26 18:53:21 +00:00
hosts * api . Endpoints
path string
2015-06-29 16:54:43 +00:00
readOnly bool
2015-03-26 18:53:21 +00:00
exe exec . Interface
}
2016-03-23 05:12:21 +00:00
var _ volume . Mounter = & glusterfsMounter { }
2015-07-23 07:07:40 +00:00
2016-03-23 05:12:21 +00:00
func ( b * glusterfsMounter ) GetAttributes ( ) volume . Attributes {
2015-10-30 20:25:36 +00:00
return volume . Attributes {
2016-01-11 16:10:55 +00:00
ReadOnly : b . readOnly ,
Managed : false ,
SupportsSELinux : false ,
2015-10-30 20:25:36 +00:00
}
2015-10-20 18:49:39 +00:00
}
2015-03-26 18:53:21 +00:00
// SetUp attaches the disk and bind mounts to the volume path.
2016-03-23 05:12:21 +00:00
func ( b * glusterfsMounter ) SetUp ( fsGroup * int64 ) error {
2015-12-18 15:55:11 +00:00
return b . SetUpAt ( b . GetPath ( ) , fsGroup )
2015-03-26 18:53:21 +00:00
}
2016-03-23 05:12:21 +00:00
func ( b * glusterfsMounter ) SetUpAt ( dir string , fsGroup * int64 ) error {
2015-04-16 23:49:53 +00:00
notMnt , err := b . mounter . IsLikelyNotMountPoint ( dir )
2015-10-07 16:47:11 +00:00
glog . V ( 4 ) . Infof ( "glusterfs: mount set up: %s %v %v" , dir , ! notMnt , err )
2015-03-26 18:53:21 +00:00
if err != nil && ! os . IsNotExist ( err ) {
return err
}
2015-04-16 23:49:53 +00:00
if ! notMnt {
2015-03-26 18:53:21 +00:00
return nil
}
2015-04-03 01:08:04 +00:00
2015-03-26 18:53:21 +00:00
os . MkdirAll ( dir , 0750 )
2015-07-23 07:07:40 +00:00
err = b . setUpAtInternal ( dir )
2015-03-26 18:53:21 +00:00
if err == nil {
return nil
}
2015-04-03 01:08:04 +00:00
// Cleanup upon failure.
2016-03-23 05:12:21 +00:00
c := & glusterfsUnmounter { b . glusterfs }
2015-07-23 07:07:40 +00:00
c . cleanup ( dir )
2015-03-26 18:53:21 +00:00
return err
}
func ( glusterfsVolume * glusterfs ) GetPath ( ) string {
name := glusterfsPluginName
2016-01-11 07:55:51 +00:00
return glusterfsVolume . plugin . host . GetPodVolumeDir ( glusterfsVolume . pod . UID , strings . EscapeQualifiedNameForDisk ( name ) , glusterfsVolume . volName )
2015-03-26 18:53:21 +00:00
}
2016-03-23 05:12:21 +00:00
type glusterfsUnmounter struct {
2015-07-23 07:07:40 +00:00
* glusterfs
}
2016-03-23 05:12:21 +00:00
var _ volume . Unmounter = & glusterfsUnmounter { }
2015-07-23 07:07:40 +00:00
2016-03-23 05:12:21 +00:00
func ( c * glusterfsUnmounter ) TearDown ( ) error {
2015-07-23 07:07:40 +00:00
return c . TearDownAt ( c . GetPath ( ) )
2015-03-26 18:53:21 +00:00
}
2016-03-23 05:12:21 +00:00
func ( c * glusterfsUnmounter ) TearDownAt ( dir string ) error {
2015-07-23 07:07:40 +00:00
return c . cleanup ( dir )
2015-03-26 18:53:21 +00:00
}
2016-03-23 05:12:21 +00:00
func ( c * glusterfsUnmounter ) cleanup ( dir string ) error {
2015-04-16 23:49:53 +00:00
notMnt , err := c . mounter . IsLikelyNotMountPoint ( dir )
2015-03-26 18:53:21 +00:00
if err != nil {
2015-10-07 16:47:11 +00:00
return fmt . Errorf ( "glusterfs: Error checking IsLikelyNotMountPoint: %v" , err )
2015-03-26 18:53:21 +00:00
}
2015-04-16 23:49:53 +00:00
if notMnt {
2015-03-26 18:53:21 +00:00
return os . RemoveAll ( dir )
}
2015-07-23 07:07:40 +00:00
if err := c . mounter . Unmount ( dir ) ; err != nil {
2015-10-07 16:47:11 +00:00
return fmt . Errorf ( "glusterfs: Unmounting failed: %v" , err )
2015-03-26 18:53:21 +00:00
}
2015-04-16 23:49:53 +00:00
notMnt , mntErr := c . mounter . IsLikelyNotMountPoint ( dir )
2015-03-26 18:53:21 +00:00
if mntErr != nil {
2015-10-07 16:47:11 +00:00
return fmt . Errorf ( "glusterfs: IsLikelyNotMountPoint check failed: %v" , mntErr )
2015-03-26 18:53:21 +00:00
}
2015-04-16 23:49:53 +00:00
if notMnt {
2015-03-26 18:53:21 +00:00
if err := os . RemoveAll ( dir ) ; err != nil {
2015-10-07 16:47:11 +00:00
return fmt . Errorf ( "glusterfs: RemoveAll failed: %v" , err )
2015-03-26 18:53:21 +00:00
}
}
return nil
}
2016-03-23 05:12:21 +00:00
func ( b * glusterfsMounter ) setUpAtInternal ( dir string ) error {
2015-03-26 18:53:21 +00:00
var errs error
2015-04-03 01:08:04 +00:00
options := [ ] string { }
2015-07-24 19:04:03 +00:00
if b . readOnly {
2015-04-03 01:08:04 +00:00
options = append ( options , "ro" )
2015-03-26 18:53:21 +00:00
}
2015-09-11 13:23:19 +00:00
p := path . Join ( b . glusterfs . plugin . host . GetPluginDir ( glusterfsPluginName ) , b . glusterfs . volName )
if err := os . MkdirAll ( p , 0750 ) ; err != nil {
2015-10-07 16:47:11 +00:00
return fmt . Errorf ( "glusterfs: mkdir failed: %v" , err )
2015-09-11 13:23:19 +00:00
}
2016-04-26 17:06:30 +00:00
// adding log-level ERROR to remove noise
// and more specific log path so each pod has
2016-10-03 09:29:50 +00:00
// its own log based on PV + Pod
2016-04-26 17:06:30 +00:00
log := path . Join ( p , b . pod . Name + "-glusterfs.log" )
options = append ( options , "log-level=ERROR" )
2015-09-11 13:23:19 +00:00
options = append ( options , "log-file=" + log )
addr := make ( map [ string ] struct { } )
for _ , s := range b . hosts . Subsets {
for _ , a := range s . Addresses {
addr [ a . IP ] = struct { } { }
}
}
2015-04-03 01:08:04 +00:00
// Avoid mount storm, pick a host randomly.
// Iterate all hosts until mount succeeds.
2015-09-11 13:23:19 +00:00
for hostIP := range addr {
2015-07-23 07:07:40 +00:00
errs = b . mounter . Mount ( hostIP + ":" + b . path , dir , "glusterfs" , options )
2015-03-26 18:53:21 +00:00
if errs == nil {
2016-04-26 17:06:30 +00:00
glog . Infof ( "glusterfs: successfully mounted %s" , dir )
2015-03-26 18:53:21 +00:00
return nil
}
}
2016-04-26 17:06:30 +00:00
// Failed mount scenario.
2016-10-03 09:29:50 +00:00
// Since gluster does not return error text
2016-04-26 17:06:30 +00:00
// it all goes in a log file, we will read the log file
logerror := readGlusterLog ( log , b . pod . Name )
if logerror != nil {
// return fmt.Errorf("glusterfs: mount failed: %v", logerror)
return fmt . Errorf ( "glusterfs: mount failed: %v the following error information was pulled from the glusterfs log to help diagnose this issue: %v" , errs , logerror )
}
2015-10-07 16:47:11 +00:00
return fmt . Errorf ( "glusterfs: mount failed: %v" , errs )
2015-03-26 18:53:21 +00:00
}
2016-05-30 22:48:21 +00:00
2016-05-30 02:22:22 +00:00
func getVolumeSource (
spec * volume . Spec ) ( * api . GlusterfsVolumeSource , bool , error ) {
2016-05-30 22:48:21 +00:00
if spec . Volume != nil && spec . Volume . Glusterfs != nil {
2016-05-30 02:22:22 +00:00
return spec . Volume . Glusterfs , spec . Volume . Glusterfs . ReadOnly , nil
} else if spec . PersistentVolume != nil &&
spec . PersistentVolume . Spec . Glusterfs != nil {
return spec . PersistentVolume . Spec . Glusterfs , spec . ReadOnly , nil
2016-05-30 22:48:21 +00:00
}
2016-05-30 02:22:22 +00:00
return nil , false , fmt . Errorf ( "Spec does not reference a Gluster volume type" )
2016-05-30 22:48:21 +00:00
}
2016-08-19 15:25:39 +00:00
func ( plugin * glusterfsPlugin ) NewProvisioner ( options volume . VolumeOptions ) ( volume . Provisioner , error ) {
if len ( options . AccessModes ) == 0 {
options . AccessModes = plugin . GetAccessModes ( )
}
return plugin . newProvisionerInternal ( options )
}
func ( plugin * glusterfsPlugin ) newProvisionerInternal ( options volume . VolumeOptions ) ( volume . Provisioner , error ) {
return & glusterfsVolumeProvisioner {
glusterfsMounter : & glusterfsMounter {
glusterfs : & glusterfs {
plugin : plugin ,
} ,
} ,
options : options ,
} , nil
}
2016-09-20 14:24:30 +00:00
type provisioningConfig struct {
endpoint string
url string
user string
userKey string
secretNamespace string
secretName string
secretValue string
2016-08-19 15:25:39 +00:00
}
type glusterfsVolumeProvisioner struct {
* glusterfsMounter
2016-09-20 14:24:30 +00:00
provisioningConfig
2016-08-19 15:25:39 +00:00
options volume . VolumeOptions
}
func ( plugin * glusterfsPlugin ) NewDeleter ( spec * volume . Spec ) ( volume . Deleter , error ) {
return plugin . newDeleterInternal ( spec )
}
func ( plugin * glusterfsPlugin ) newDeleterInternal ( spec * volume . Spec ) ( volume . Deleter , error ) {
if spec . PersistentVolume != nil && spec . PersistentVolume . Spec . Glusterfs == nil {
return nil , fmt . Errorf ( "spec.PersistentVolumeSource.Spec.Glusterfs is nil" )
}
return & glusterfsVolumeDeleter {
glusterfsMounter : & glusterfsMounter {
glusterfs : & glusterfs {
volName : spec . Name ( ) ,
plugin : plugin ,
} ,
path : spec . PersistentVolume . Spec . Glusterfs . Path ,
2016-09-20 14:24:30 +00:00
} ,
spec : spec . PersistentVolume ,
} , nil
2016-08-19 15:25:39 +00:00
}
type glusterfsVolumeDeleter struct {
* glusterfsMounter
2016-09-20 14:24:30 +00:00
provisioningConfig
spec * api . PersistentVolume
2016-08-19 15:25:39 +00:00
}
func ( d * glusterfsVolumeDeleter ) GetPath ( ) string {
name := glusterfsPluginName
return d . plugin . host . GetPodVolumeDir ( d . glusterfsMounter . glusterfs . pod . UID , strings . EscapeQualifiedNameForDisk ( name ) , d . glusterfsMounter . glusterfs . volName )
}
func ( d * glusterfsVolumeDeleter ) Delete ( ) error {
var err error
2016-09-20 14:24:30 +00:00
glog . V ( 2 ) . Infof ( "glusterfs: delete volume: %s " , d . glusterfsMounter . path )
volumeName := d . glusterfsMounter . path
volumeId := dstrings . TrimPrefix ( volumeName , volprefix )
err = d . annotationsToParam ( d . spec )
if err != nil {
return err
}
if len ( d . secretName ) > 0 {
d . secretValue , err = parseSecret ( d . secretNamespace , d . secretName , d . plugin . host . GetKubeClient ( ) )
if err != nil {
glog . Errorf ( "glusterfs: failed to read secret: %v" , err )
return err
}
} else if len ( d . userKey ) > 0 {
d . secretValue = d . userKey
} else {
d . secretValue = ""
}
glog . V ( 4 ) . Infof ( "glusterfs: deleting volume %q with configuration %+v" , volumeId , d . provisioningConfig )
cli := gcli . NewClient ( d . url , d . user , d . secretValue )
2016-08-19 15:25:39 +00:00
if cli == nil {
glog . Errorf ( "glusterfs: failed to create gluster rest client" )
return fmt . Errorf ( "glusterfs: failed to create gluster rest client, REST server authentication failed" )
}
2016-09-20 14:24:30 +00:00
err = cli . VolumeDelete ( volumeId )
2016-08-19 15:25:39 +00:00
if err != nil {
glog . V ( 4 ) . Infof ( "glusterfs: error when deleting the volume :%s" , err )
return err
}
2016-09-20 14:24:30 +00:00
glog . V ( 2 ) . Infof ( "glusterfs: volume %s deleted successfully" , volumeName )
2016-08-19 15:25:39 +00:00
return nil
}
func ( r * glusterfsVolumeProvisioner ) Provision ( ) ( * api . PersistentVolume , error ) {
var err error
if r . options . Selector != nil {
glog . V ( 4 ) . Infof ( "glusterfs: not able to parse your claim Selector" )
return nil , fmt . Errorf ( "glusterfs: not able to parse your claim Selector" )
}
glog . V ( 4 ) . Infof ( "glusterfs: Provison VolumeOptions %v" , r . options )
2016-09-20 14:24:30 +00:00
authEnabled := true
2016-08-19 15:25:39 +00:00
for k , v := range r . options . Parameters {
switch dstrings . ToLower ( k ) {
case "endpoint" :
2016-09-20 14:24:30 +00:00
r . endpoint = v
2016-08-19 15:25:39 +00:00
case "resturl" :
2016-09-20 14:24:30 +00:00
r . url = v
2016-08-19 15:25:39 +00:00
case "restuser" :
2016-09-20 14:24:30 +00:00
r . user = v
2016-08-19 15:25:39 +00:00
case "restuserkey" :
2016-09-20 14:24:30 +00:00
r . userKey = v
case "secretname" :
r . secretName = v
case "secretnamespace" :
r . secretNamespace = v
case "restauthenabled" :
authEnabled = dstrings . ToLower ( v ) == "true"
2016-08-19 15:25:39 +00:00
default :
return nil , fmt . Errorf ( "glusterfs: invalid option %q for volume plugin %s" , k , r . plugin . GetPluginName ( ) )
}
}
2016-09-20 14:24:30 +00:00
if len ( r . url ) == 0 {
return nil , fmt . Errorf ( "StorageClass for provisioner %q must contain 'resturl' parameter" , r . plugin . GetPluginName ( ) )
}
if len ( r . endpoint ) == 0 {
return nil , fmt . Errorf ( "StorageClass for provisioner %q must contain 'endpoint' parameter" , r . plugin . GetPluginName ( ) )
}
if ! authEnabled {
r . user = ""
r . secretName = ""
r . secretNamespace = ""
r . userKey = ""
r . secretValue = ""
}
if len ( r . secretName ) != 0 || len ( r . secretNamespace ) != 0 {
// secretName + Namespace has precedence over userKey
if len ( r . secretName ) != 0 && len ( r . secretNamespace ) != 0 {
r . secretValue , err = parseSecret ( r . secretNamespace , r . secretName , r . plugin . host . GetKubeClient ( ) )
if err != nil {
return nil , err
}
} else {
return nil , fmt . Errorf ( "StorageClass for provisioner %q must have secretNamespace and secretName either both set or both empty" , r . plugin . GetPluginName ( ) )
}
} else {
r . secretValue = r . userKey
2016-08-19 15:25:39 +00:00
}
2016-09-20 14:24:30 +00:00
glog . V ( 4 ) . Infof ( "glusterfs: creating volume with configuration %+v" , r . provisioningConfig )
2016-08-19 15:25:39 +00:00
glusterfs , sizeGB , err := r . CreateVolume ( )
if err != nil {
glog . Errorf ( "glusterfs: create volume err: %s." , err )
return nil , fmt . Errorf ( "glusterfs: create volume err: %s." , err )
}
pv := new ( api . PersistentVolume )
pv . Spec . PersistentVolumeSource . Glusterfs = glusterfs
pv . Spec . PersistentVolumeReclaimPolicy = r . options . PersistentVolumeReclaimPolicy
pv . Spec . AccessModes = r . options . AccessModes
pv . Spec . Capacity = api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( fmt . Sprintf ( "%dGi" , sizeGB ) ) ,
}
2016-09-20 14:24:30 +00:00
r . paramToAnnotations ( pv )
2016-08-19 15:25:39 +00:00
return pv , nil
}
func ( p * glusterfsVolumeProvisioner ) CreateVolume ( ) ( r * api . GlusterfsVolumeSource , size int , err error ) {
volSizeBytes := p . options . Capacity . Value ( )
sz := int ( volume . RoundUpSize ( volSizeBytes , 1024 * 1024 * 1024 ) )
2016-09-20 14:24:30 +00:00
glog . V ( 2 ) . Infof ( "glusterfs: create volume of size: %d bytes and configuration %+v" , volSizeBytes , p . provisioningConfig )
if p . url == "" {
2016-08-19 15:25:39 +00:00
glog . Errorf ( "glusterfs : rest server endpoint is empty" )
return nil , 0 , fmt . Errorf ( "failed to create gluster REST client, REST URL is empty" )
}
2016-09-20 14:24:30 +00:00
cli := gcli . NewClient ( p . url , p . user , p . secretValue )
2016-08-19 15:25:39 +00:00
if cli == nil {
glog . Errorf ( "glusterfs: failed to create gluster rest client" )
return nil , 0 , fmt . Errorf ( "failed to create gluster REST client, REST server authentication failed" )
}
2016-09-14 11:38:37 +00:00
volumeReq := & gapi . VolumeCreateRequest { Size : sz , Durability : gapi . VolumeDurabilityInfo { Type : durabilitytype , Replicate : gapi . ReplicaDurability { Replica : replicacount } } }
2016-08-19 15:25:39 +00:00
volume , err := cli . VolumeCreate ( volumeReq )
if err != nil {
glog . Errorf ( "glusterfs: error creating volume %s " , err )
return nil , 0 , fmt . Errorf ( "error creating volume %v" , err )
}
2016-09-20 14:24:30 +00:00
glog . V ( 1 ) . Infof ( "glusterfs: volume with size: %d and name: %s created" , volume . Size , volume . Name )
2016-08-19 15:25:39 +00:00
return & api . GlusterfsVolumeSource {
2016-09-20 14:24:30 +00:00
EndpointsName : p . endpoint ,
2016-08-19 15:25:39 +00:00
Path : volume . Name ,
ReadOnly : false ,
} , sz , nil
}
2016-09-20 14:24:30 +00:00
// parseSecret finds a given Secret instance and reads user password from it.
func parseSecret ( namespace , secretName string , kubeClient clientset . Interface ) ( string , error ) {
secretMap , err := volutil . GetSecret ( namespace , secretName , kubeClient )
if err != nil {
glog . Errorf ( "failed to get secret from [%q/%q]" , namespace , secretName )
return "" , fmt . Errorf ( "failed to get secret from [%q/%q]" , namespace , secretName )
}
if len ( secretMap ) == 0 {
return "" , fmt . Errorf ( "empty secret map" )
}
secret := ""
for k , v := range secretMap {
if k == secretKeyName {
return v , nil
}
secret = v
}
// If not found, the last secret in the map wins as done before
return secret , nil
}
// paramToAnnotations stores parameters needed to delete the volume in the PV
// annotations.
func ( p * glusterfsVolumeProvisioner ) paramToAnnotations ( pv * api . PersistentVolume ) {
ann := map [ string ] string {
annGlusterURL : p . url ,
annGlusterUser : p . user ,
annGlusterSecretName : p . secretName ,
annGlusterSecretNamespace : p . secretNamespace ,
annGlusterUserKey : p . userKey ,
}
volutil . AddVolumeAnnotations ( pv , ann )
}
// annotationsToParam parses annotations stored by paramToAnnotations
func ( d * glusterfsVolumeDeleter ) annotationsToParam ( pv * api . PersistentVolume ) error {
annKeys := [ ] string {
annGlusterSecretName ,
annGlusterSecretNamespace ,
annGlusterURL ,
annGlusterUser ,
annGlusterUserKey ,
}
params , err := volutil . ParseVolumeAnnotations ( pv , annKeys )
if err != nil {
return err
}
d . url = params [ annGlusterURL ]
d . user = params [ annGlusterUser ]
d . userKey = params [ annGlusterUserKey ]
d . secretName = params [ annGlusterSecretName ]
d . secretNamespace = params [ annGlusterSecretNamespace ]
return nil
}