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-12-02 01:16:23 +00:00
"math"
2016-09-20 14:24:30 +00:00
"os"
"path"
2016-11-18 20:58:56 +00:00
"runtime"
2016-12-02 01:16:23 +00:00
"strconv"
2016-09-20 14:24:30 +00:00
dstrings "strings"
2016-12-02 03:02:07 +00:00
"sync"
2016-09-20 14:24:30 +00:00
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"
2017-01-13 17:48:50 +00:00
"k8s.io/apimachinery/pkg/api/errors"
2017-01-25 13:13:07 +00:00
"k8s.io/apimachinery/pkg/api/resource"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
2016-11-18 20:58:56 +00:00
"k8s.io/kubernetes/pkg/api/v1"
2016-12-02 03:02:07 +00:00
storageutil "k8s.io/kubernetes/pkg/apis/storage/v1beta1/util"
2017-01-10 08:49:34 +00:00
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
2015-08-05 22:03:47 +00:00
"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"
2016-12-02 03:02:07 +00:00
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
2015-03-26 18:53:21 +00:00
)
// This is the primary entrypoint for volume plugins.
func ProbeVolumePlugins ( ) [ ] volume . VolumePlugin {
2016-12-02 03:02:07 +00:00
return [ ] volume . VolumePlugin { & glusterfsPlugin { host : nil , exe : exec . New ( ) , gidTable : make ( map [ string ] * MinMaxAllocator ) } }
2015-03-26 18:53:21 +00:00
}
type glusterfsPlugin struct {
2016-12-02 03:02:07 +00:00
host volume . VolumeHost
exe exec . Interface
gidTable map [ string ] * MinMaxAllocator
gidTableLock sync . Mutex
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-11-12 01:30:20 +00:00
glusterfsPluginName = "kubernetes.io/glusterfs"
volPrefix = "vol_"
dynamicEpSvcPrefix = "glusterfs-dynamic-"
replicaCount = 3
durabilityType = "replicate"
secretKeyName = "key" // key name used in secret
gciGlusterMountBinariesPath = "/sbin/mount.glusterfs"
2016-12-02 01:16:23 +00:00
defaultGidMin = 2000
2016-12-05 21:33:35 +00:00
defaultGidMax = math . MaxInt32
2016-12-08 10:10:14 +00:00
// absoluteGidMin/Max are currently the same as the
// default values, but they play a different role and
// could take a different value. Only thing we need is:
// absGidMin <= defGidMin <= defGidMax <= absGidMax
absoluteGidMin = 2000
absoluteGidMax = math . MaxInt32
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
}
2016-11-18 20:58:56 +00:00
func ( plugin * glusterfsPlugin ) GetAccessModes ( ) [ ] v1 . PersistentVolumeAccessMode {
return [ ] v1 . PersistentVolumeAccessMode {
v1 . ReadWriteOnce ,
v1 . ReadOnlyMany ,
v1 . ReadWriteMany ,
2015-03-26 18:53:21 +00:00
}
}
2016-11-18 20:58:56 +00:00
func ( plugin * glusterfsPlugin ) NewMounter ( spec * volume . Spec , pod * v1 . 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
2016-10-19 16:23:17 +00:00
// PVC/POD is in same ns.
2015-05-11 00:12:57 +00:00
ns := pod . Namespace
2016-12-20 09:06:35 +00:00
kubeClient := plugin . host . GetKubeClient ( )
if kubeClient == nil {
return nil , fmt . Errorf ( "glusterfs: failed to get kube client to initialize mounter" )
}
ep , err := kubeClient . Core ( ) . Endpoints ( ns ) . Get ( ep_name , metav1 . GetOptions { } )
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
}
2016-11-18 20:58:56 +00:00
func ( plugin * glusterfsPlugin ) getGlusterVolumeSource ( spec * volume . Spec ) ( * v1 . GlusterfsVolumeSource , bool ) {
2015-06-26 20:37:11 +00:00
// 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-11-18 20:58:56 +00:00
func ( plugin * glusterfsPlugin ) newMounterInternal ( spec * volume . Spec , ep * v1 . Endpoints , pod * v1 . 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 ,
2017-01-17 03:38:19 +00:00
pod : & v1 . Pod { ObjectMeta : metav1 . 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 ) {
2016-11-18 20:58:56 +00:00
glusterfsVolume := & v1 . Volume {
2016-06-23 19:46:21 +00:00
Name : volumeName ,
2016-11-18 20:58:56 +00:00
VolumeSource : v1 . VolumeSource {
Glusterfs : & v1 . GlusterfsVolumeSource {
2016-06-23 19:46:21 +00:00
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
2016-11-18 20:58:56 +00:00
pod * v1 . Pod
2015-07-23 07:07:40 +00:00
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
2016-11-18 20:58:56 +00:00
hosts * v1 . Endpoints
2015-03-26 18:53:21 +00:00
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
}
2016-11-03 19:15:52 +00:00
// Checks prior to mount operations to verify that the required components (binaries, etc.)
// to mount the volume are available on the underlying node.
// If not, it returns an error
func ( b * glusterfsMounter ) CanMount ( ) error {
2016-11-12 01:30:20 +00:00
exe := exec . New ( )
switch runtime . GOOS {
case "linux" :
if _ , err := exe . Command ( "/bin/ls" , gciGlusterMountBinariesPath ) . CombinedOutput ( ) ; err != nil {
return fmt . Errorf ( "Required binary %s is missing" , gciGlusterMountBinariesPath )
}
}
2016-11-03 19:15:52 +00:00
return nil
}
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-12-20 00:40:55 +00:00
volutil . UnmountPath ( dir , b . mounter )
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 {
2016-12-20 00:40:55 +00:00
return volutil . UnmountPath ( dir , c . mounter )
2015-03-26 18:53:21 +00:00
}
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 )
2016-10-19 16:23:17 +00:00
var addrlist [ ] string
if b . hosts == nil {
return fmt . Errorf ( "glusterfs: endpoint is nil" )
} else {
addr := make ( map [ string ] struct { } )
if b . hosts . Subsets != nil {
for _ , s := range b . hosts . Subsets {
for _ , a := range s . Addresses {
addr [ a . IP ] = struct { } { }
addrlist = append ( addrlist , a . IP )
}
}
2015-09-11 13:23:19 +00:00
}
2016-10-19 16:23:17 +00:00
// Avoid mount storm, pick a host randomly.
// Iterate all hosts until mount succeeds.
for _ , ip := range addrlist {
errs = b . mounter . Mount ( ip + ":" + b . path , dir , "glusterfs" , options )
if errs == nil {
glog . Infof ( "glusterfs: successfully mounted %s" , dir )
return nil
}
2015-03-26 18:53:21 +00:00
}
}
2016-04-26 17:06:30 +00:00
// Failed mount scenario.
2016-10-27 03:58:08 +00:00
// Since glusterfs 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 (
2016-11-18 20:58:56 +00:00
spec * volume . Spec ) ( * v1 . 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-10-27 03:58:08 +00:00
return nil , false , fmt . Errorf ( "Spec does not reference a GlusterFS 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 ) {
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
}
2017-01-31 09:01:55 +00:00
type provisionerConfig struct {
2016-09-20 14:24:30 +00:00
url string
user string
userKey string
secretNamespace string
secretName string
secretValue string
2016-11-23 07:27:35 +00:00
clusterId string
2016-12-05 21:33:35 +00:00
gidMin int
gidMax int
2017-01-06 07:03:25 +00:00
volumeType gapi . VolumeDurabilityInfo
2016-08-19 15:25:39 +00:00
}
type glusterfsVolumeProvisioner struct {
* glusterfsMounter
2017-01-31 09:01:55 +00:00
provisionerConfig
2016-08-19 15:25:39 +00:00
options volume . VolumeOptions
}
2016-12-05 21:33:35 +00:00
func convertGid ( gidString string ) ( int , error ) {
gid64 , err := strconv . ParseInt ( gidString , 10 , 32 )
2016-12-02 01:16:23 +00:00
if err != nil {
2016-12-05 21:33:35 +00:00
return 0 , fmt . Errorf ( "glusterfs: failed to parse gid %v " , gidString )
2016-12-02 01:16:23 +00:00
}
2016-12-05 21:33:35 +00:00
if gid64 < 0 {
return 0 , fmt . Errorf ( "glusterfs: negative GIDs are not allowed: %v" , gidString )
}
// ParseInt returns a int64, but since we parsed only
// for 32 bit, we can cast to int without loss:
gid := int ( gid64 )
return gid , nil
2016-12-02 01:16:23 +00:00
}
2017-01-06 07:03:25 +00:00
func convertVolumeParam ( volumeString string ) ( int , error ) {
count , err := strconv . Atoi ( volumeString )
if err != nil {
return 0 , fmt . Errorf ( "failed to parse %q" , volumeString )
}
if count < 0 {
return 0 , fmt . Errorf ( "negative values are not allowed" )
}
return count , nil
}
2016-08-19 15:25:39 +00:00
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
2017-01-31 09:01:55 +00:00
provisionerConfig
2016-11-18 20:58:56 +00:00
spec * v1 . 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 )
}
2016-12-02 03:02:07 +00:00
//
// Traverse the PVs, fetching all the GIDs from those
// in a given storage class, and mark them in the table.
//
func ( p * glusterfsPlugin ) collectGids ( className string , gidTable * MinMaxAllocator ) error {
2016-12-20 09:06:35 +00:00
kubeClient := p . host . GetKubeClient ( )
if kubeClient == nil {
return fmt . Errorf ( "glusterfs: failed to get kube client when collecting gids" )
}
2017-01-22 00:05:19 +00:00
pvList , err := kubeClient . Core ( ) . PersistentVolumes ( ) . List ( metav1 . ListOptions { LabelSelector : labels . Everything ( ) . String ( ) } )
2016-12-02 03:02:07 +00:00
if err != nil {
glog . Errorf ( "glusterfs: failed to get existing persistent volumes" )
return err
}
for _ , pv := range pvList . Items {
if storageutil . GetVolumeStorageClass ( & pv ) != className {
continue
}
pvName := pv . ObjectMeta . Name
gidStr , ok := pv . Annotations [ volumehelper . VolumeGidAnnotationKey ]
if ! ok {
glog . Warningf ( "glusterfs: no gid found in pv '%v'" , pvName )
continue
}
gid , err := convertGid ( gidStr )
if err != nil {
glog . Error ( err )
continue
}
2016-12-05 21:33:35 +00:00
_ , err = gidTable . Allocate ( gid )
2016-12-02 03:02:07 +00:00
if err == ErrConflict {
glog . Warningf ( "glusterfs: gid %v found in pv %v was already allocated" , gid )
} else if err != nil {
glog . Errorf ( "glusterfs: failed to store gid %v found in pv '%v': %v" , gid , pvName , err )
return err
}
}
return nil
}
//
// Return the gid table for a storage class.
// - If this is the first time, fill it with all the gids
// used in PVs of this storage class by traversing the PVs.
// - Adapt the range of the table to the current range of the SC.
//
2016-12-05 21:33:35 +00:00
func ( p * glusterfsPlugin ) getGidTable ( className string , min int , max int ) ( * MinMaxAllocator , error ) {
2016-12-02 03:02:07 +00:00
var err error
p . gidTableLock . Lock ( )
gidTable , ok := p . gidTable [ className ]
p . gidTableLock . Unlock ( )
if ok {
2016-12-05 21:33:35 +00:00
err = gidTable . SetRange ( min , max )
2016-12-02 03:02:07 +00:00
if err != nil {
return nil , err
}
return gidTable , nil
}
// create a new table and fill it
newGidTable , err := NewMinMaxAllocator ( 0 , absoluteGidMax )
if err != nil {
return nil , err
}
// collect gids with the full range
err = p . collectGids ( className , newGidTable )
if err != nil {
return nil , err
}
// and only reduce the range afterwards
2016-12-05 21:33:35 +00:00
err = newGidTable . SetRange ( min , max )
2016-12-02 03:02:07 +00:00
if err != nil {
return nil , err
}
// if in the meantime a table appeared, use it
p . gidTableLock . Lock ( )
defer p . gidTableLock . Unlock ( )
gidTable , ok = p . gidTable [ className ]
if ok {
2016-12-05 21:33:35 +00:00
err = gidTable . SetRange ( min , max )
2016-12-02 03:02:07 +00:00
if err != nil {
return nil , err
}
return gidTable , nil
}
p . gidTable [ className ] = newGidTable
return newGidTable , nil
}
2016-12-05 21:33:35 +00:00
func ( d * glusterfsVolumeDeleter ) getGid ( ) ( int , bool , error ) {
2016-12-02 03:02:07 +00:00
gidStr , ok := d . spec . Annotations [ volumehelper . VolumeGidAnnotationKey ]
if ! ok {
return 0 , false , nil
}
gid , err := convertGid ( gidStr )
return gid , true , err
}
2016-08-19 15:25:39 +00:00
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
2016-10-19 16:23:17 +00:00
volumeId := dstrings . TrimPrefix ( volumeName , volPrefix )
2016-10-18 07:54:35 +00:00
class , err := volutil . GetClassForVolume ( d . plugin . host . GetKubeClient ( ) , d . spec )
2016-09-20 14:24:30 +00:00
if err != nil {
return err
}
2016-10-18 07:54:35 +00:00
cfg , err := parseClassParameters ( class . Parameters , d . plugin . host . GetKubeClient ( ) )
if err != nil {
return err
2016-09-20 14:24:30 +00:00
}
2017-01-31 09:01:55 +00:00
d . provisionerConfig = * cfg
2016-09-20 14:24:30 +00:00
2017-01-31 09:01:55 +00:00
glog . V ( 4 ) . Infof ( "glusterfs: deleting volume %q with configuration %+v" , volumeId , d . provisionerConfig )
2016-09-20 14:24:30 +00:00
2016-12-02 03:02:07 +00:00
gid , exists , err := d . getGid ( )
if err != nil {
glog . Error ( err )
} else if exists {
gidTable , err := d . plugin . getGidTable ( class . Name , cfg . gidMin , cfg . gidMax )
if err != nil {
return fmt . Errorf ( "glusterfs: failed to get gidTable: %v" , err )
}
2016-12-05 21:33:35 +00:00
err = gidTable . Release ( gid )
2016-12-02 03:02:07 +00:00
if err != nil {
return fmt . Errorf ( "glusterfs: failed to release gid %v: %v" , gid , err )
}
}
2016-09-20 14:24:30 +00:00
cli := gcli . NewClient ( d . url , d . user , d . secretValue )
2016-08-19 15:25:39 +00:00
if cli == nil {
2016-10-27 03:58:08 +00:00
glog . Errorf ( "glusterfs: failed to create glusterfs rest client" )
return fmt . Errorf ( "glusterfs: failed to create glusterfs rest client, REST server authentication failed" )
2016-08-19 15:25:39 +00:00
}
2016-09-20 14:24:30 +00:00
err = cli . VolumeDelete ( volumeId )
2016-08-19 15:25:39 +00:00
if err != nil {
2016-10-19 16:23:17 +00:00
glog . Errorf ( "glusterfs: error when deleting the volume :%v" , err )
2016-08-19 15:25:39 +00:00
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
2016-10-19 16:23:17 +00:00
//Deleter takes endpoint and endpointnamespace from pv spec.
pvSpec := d . spec . Spec
var dynamicEndpoint , dynamicNamespace string
if pvSpec . ClaimRef == nil {
glog . Errorf ( "glusterfs: ClaimRef is nil" )
return fmt . Errorf ( "glusterfs: ClaimRef is nil" )
}
if pvSpec . ClaimRef . Namespace == "" {
glog . Errorf ( "glusterfs: namespace is nil" )
return fmt . Errorf ( "glusterfs: namespace is nil" )
}
dynamicNamespace = pvSpec . ClaimRef . Namespace
if pvSpec . Glusterfs . EndpointsName != "" {
dynamicEndpoint = pvSpec . Glusterfs . EndpointsName
}
glog . V ( 3 ) . Infof ( "glusterfs: dynamic namespace and endpoint : [%v/%v]" , dynamicNamespace , dynamicEndpoint )
err = d . deleteEndpointService ( dynamicNamespace , dynamicEndpoint )
if err != nil {
glog . Errorf ( "glusterfs: error when deleting endpoint/service :%v" , err )
} else {
glog . V ( 1 ) . Infof ( "glusterfs: [%v/%v] deleted successfully " , dynamicNamespace , dynamicEndpoint )
}
return nil
2016-08-19 15:25:39 +00:00
}
2016-11-18 20:58:56 +00:00
func ( r * glusterfsVolumeProvisioner ) Provision ( ) ( * v1 . PersistentVolume , error ) {
2016-08-19 15:25:39 +00:00
var err error
2016-10-12 10:22:01 +00:00
if r . options . PVC . Spec . Selector != nil {
2016-08-19 15:25:39 +00:00
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-12-02 03:02:07 +00:00
scName := storageutil . GetClaimStorageClass ( r . options . PVC )
2016-10-18 07:54:35 +00:00
cfg , err := parseClassParameters ( r . options . Parameters , r . plugin . host . GetKubeClient ( ) )
if err != nil {
return nil , err
2016-08-19 15:25:39 +00:00
}
2017-01-31 09:01:55 +00:00
r . provisionerConfig = * cfg
2016-11-18 21:32:24 +00:00
2017-01-31 09:01:55 +00:00
glog . V ( 4 ) . Infof ( "glusterfs: creating volume with configuration %+v" , r . provisionerConfig )
2016-12-02 03:02:07 +00:00
gidTable , err := r . plugin . getGidTable ( scName , cfg . gidMin , cfg . gidMax )
if err != nil {
return nil , fmt . Errorf ( "glusterfs: failed to get gidTable: %v" , err )
}
gid , _ , err := gidTable . AllocateNext ( )
2016-08-19 15:25:39 +00:00
if err != nil {
2016-12-02 03:02:07 +00:00
glog . Errorf ( "glusterfs: failed to reserve gid from table: %v" , err )
return nil , fmt . Errorf ( "glusterfs: failed to reserve gid from table: %v" , err )
}
glog . V ( 2 ) . Infof ( "glusterfs: got gid [%d] for PVC %s" , gid , r . options . PVC . Name )
glusterfs , sizeGB , err := r . CreateVolume ( gid )
if err != nil {
if release_err := gidTable . Release ( gid ) ; release_err != nil {
glog . Errorf ( "glusterfs: error when releasing gid in storageclass: %s" , scName )
}
2016-10-19 16:23:17 +00:00
glog . Errorf ( "glusterfs: create volume err: %v." , err )
return nil , fmt . Errorf ( "glusterfs: create volume err: %v." , err )
2016-08-19 15:25:39 +00:00
}
2016-11-18 20:58:56 +00:00
pv := new ( v1 . PersistentVolume )
2016-08-19 15:25:39 +00:00
pv . Spec . PersistentVolumeSource . Glusterfs = glusterfs
pv . Spec . PersistentVolumeReclaimPolicy = r . options . PersistentVolumeReclaimPolicy
2016-10-12 10:22:01 +00:00
pv . Spec . AccessModes = r . options . PVC . Spec . AccessModes
if len ( pv . Spec . AccessModes ) == 0 {
pv . Spec . AccessModes = r . plugin . GetAccessModes ( )
}
2016-12-02 03:02:07 +00:00
gidStr := strconv . FormatInt ( int64 ( gid ) , 10 )
pv . Annotations = map [ string ] string { volumehelper . VolumeGidAnnotationKey : gidStr }
2016-11-18 20:58:56 +00:00
pv . Spec . Capacity = v1 . ResourceList {
v1 . ResourceName ( v1 . ResourceStorage ) : resource . MustParse ( fmt . Sprintf ( "%dGi" , sizeGB ) ) ,
2016-08-19 15:25:39 +00:00
}
return pv , nil
}
2016-12-02 03:02:07 +00:00
func ( p * glusterfsVolumeProvisioner ) CreateVolume ( gid int ) ( r * v1 . GlusterfsVolumeSource , size int , err error ) {
2016-12-05 08:06:10 +00:00
var clusterIds [ ] string
2016-11-18 20:58:56 +00:00
capacity := p . options . PVC . Spec . Resources . Requests [ v1 . ResourceName ( v1 . ResourceStorage ) ]
2016-10-12 10:22:01 +00:00
volSizeBytes := capacity . Value ( )
2016-08-19 15:25:39 +00:00
sz := int ( volume . RoundUpSize ( volSizeBytes , 1024 * 1024 * 1024 ) )
2017-01-31 09:01:55 +00:00
glog . V ( 2 ) . Infof ( "glusterfs: create volume of size: %d bytes and configuration %+v" , volSizeBytes , p . provisionerConfig )
2016-09-20 14:24:30 +00:00
if p . url == "" {
2016-08-19 15:25:39 +00:00
glog . Errorf ( "glusterfs : rest server endpoint is empty" )
2016-10-27 03:58:08 +00:00
return nil , 0 , fmt . Errorf ( "failed to create glusterfs REST client, REST URL is empty" )
2016-08-19 15:25:39 +00:00
}
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 {
2016-10-27 03:58:08 +00:00
glog . Errorf ( "glusterfs: failed to create glusterfs rest client" )
return nil , 0 , fmt . Errorf ( "failed to create glusterfs REST client, REST server authentication failed" )
2016-08-19 15:25:39 +00:00
}
2017-01-31 09:01:55 +00:00
if p . provisionerConfig . clusterId != "" {
2016-12-05 08:06:10 +00:00
clusterIds = dstrings . Split ( p . clusterId , "," )
glog . V ( 4 ) . Infof ( "glusterfs: provided clusterids: %v" , clusterIds )
}
2016-12-02 03:02:07 +00:00
gid64 := int64 ( gid )
2017-01-13 02:41:05 +00:00
volumeReq := & gapi . VolumeCreateRequest { Size : sz , Clusters : clusterIds , Gid : gid64 , Durability : p . volumeType }
2016-08-19 15:25:39 +00:00
volume , err := cli . VolumeCreate ( volumeReq )
if err != nil {
2016-10-19 16:23:17 +00:00
glog . Errorf ( "glusterfs: error creating volume %v " , err )
2016-08-19 15:25:39 +00:00
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-10-19 16:23:17 +00:00
clusterinfo , err := cli . ClusterInfo ( volume . Cluster )
if err != nil {
2016-11-14 14:16:09 +00:00
glog . Errorf ( "glusterfs: failed to get cluster details: %v" , err )
return nil , 0 , fmt . Errorf ( "failed to get cluster details: %v" , err )
2016-10-19 16:23:17 +00:00
}
// For the above dynamically provisioned volume, we gather the list of node IPs
// of the cluster on which provisioned volume belongs to, as there can be multiple
// clusters.
var dynamicHostIps [ ] string
for _ , node := range clusterinfo . Nodes {
nodei , err := cli . NodeInfo ( string ( node ) )
if err != nil {
2016-11-14 14:16:09 +00:00
glog . Errorf ( "glusterfs: failed to get hostip: %v" , err )
return nil , 0 , fmt . Errorf ( "failed to get hostip: %v" , err )
2016-10-19 16:23:17 +00:00
}
ipaddr := dstrings . Join ( nodei . NodeAddRequest . Hostnames . Storage , "" )
dynamicHostIps = append ( dynamicHostIps , ipaddr )
}
glog . V ( 3 ) . Infof ( "glusterfs: hostlist :%v" , dynamicHostIps )
if len ( dynamicHostIps ) == 0 {
2016-11-14 14:16:09 +00:00
glog . Errorf ( "glusterfs: no hosts found: %v" , err )
return nil , 0 , fmt . Errorf ( "no hosts found: %v" , err )
2016-10-19 16:23:17 +00:00
}
// The 'endpointname' is created in form of 'gluster-dynamic-<claimname>'.
// createEndpointService() checks for this 'endpoint' existence in PVC's namespace and
// If not found, it create an endpoint and svc using the IPs we dynamically picked at time
// of volume creation.
epServiceName := dynamicEpSvcPrefix + p . options . PVC . Name
epNamespace := p . options . PVC . Namespace
endpoint , service , err := p . createEndpointService ( epNamespace , epServiceName , dynamicHostIps , p . options . PVC . Name )
if err != nil {
2016-11-14 14:16:09 +00:00
glog . Errorf ( "glusterfs: failed to create endpoint/service: %v" , err )
2016-10-21 11:13:07 +00:00
err = cli . VolumeDelete ( volume . Id )
if err != nil {
glog . Errorf ( "glusterfs: error when deleting the volume :%v , manual deletion required" , err )
}
2016-10-19 16:23:17 +00:00
return nil , 0 , fmt . Errorf ( "failed to create endpoint/service %v" , err )
}
glog . V ( 3 ) . Infof ( "glusterfs: dynamic ep %v and svc : %v " , endpoint , service )
2016-11-18 20:58:56 +00:00
return & v1 . GlusterfsVolumeSource {
2016-10-19 16:23:17 +00:00
EndpointsName : endpoint . Name ,
2016-08-19 15:25:39 +00:00
Path : volume . Name ,
ReadOnly : false ,
} , sz , nil
}
2016-09-20 14:24:30 +00:00
2016-11-18 20:58:56 +00:00
func ( p * glusterfsVolumeProvisioner ) createEndpointService ( namespace string , epServiceName string , hostips [ ] string , pvcname string ) ( endpoint * v1 . Endpoints , service * v1 . Service , err error ) {
2016-10-19 16:23:17 +00:00
2016-11-18 20:58:56 +00:00
addrlist := make ( [ ] v1 . EndpointAddress , len ( hostips ) )
2016-10-19 16:23:17 +00:00
for i , v := range hostips {
addrlist [ i ] . IP = v
}
2016-11-18 20:58:56 +00:00
endpoint = & v1 . Endpoints {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-10-19 16:23:17 +00:00
Namespace : namespace ,
Name : epServiceName ,
Labels : map [ string ] string {
"gluster.kubernetes.io/provisioned-for-pvc" : pvcname ,
} ,
} ,
2016-11-18 20:58:56 +00:00
Subsets : [ ] v1 . EndpointSubset { {
2016-10-19 16:23:17 +00:00
Addresses : addrlist ,
2016-11-18 20:58:56 +00:00
Ports : [ ] v1 . EndpointPort { { Port : 1 , Protocol : "TCP" } } ,
2016-10-19 16:23:17 +00:00
} } ,
}
2016-12-20 09:06:35 +00:00
kubeClient := p . plugin . host . GetKubeClient ( )
if kubeClient == nil {
return nil , nil , fmt . Errorf ( "glusterfs: failed to get kube client when creating endpoint service" )
}
_ , err = kubeClient . Core ( ) . Endpoints ( namespace ) . Create ( endpoint )
2016-10-19 16:23:17 +00:00
if err != nil && errors . IsAlreadyExists ( err ) {
glog . V ( 1 ) . Infof ( "glusterfs: endpoint [%s] already exist in namespace [%s]" , endpoint , namespace )
err = nil
}
if err != nil {
2016-11-14 14:16:09 +00:00
glog . Errorf ( "glusterfs: failed to create endpoint: %v" , err )
return nil , nil , fmt . Errorf ( "error creating endpoint: %v" , err )
2016-10-19 16:23:17 +00:00
}
2016-11-18 20:58:56 +00:00
service = & v1 . Service {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-10-19 16:23:17 +00:00
Name : epServiceName ,
Namespace : namespace ,
Labels : map [ string ] string {
"gluster.kubernetes.io/provisioned-for-pvc" : pvcname ,
} ,
} ,
2016-11-18 20:58:56 +00:00
Spec : v1 . ServiceSpec {
Ports : [ ] v1 . ServicePort {
2016-10-19 16:23:17 +00:00
{ Protocol : "TCP" , Port : 1 } } } }
2016-12-20 09:06:35 +00:00
_ , err = kubeClient . Core ( ) . Services ( namespace ) . Create ( service )
2016-10-19 16:23:17 +00:00
if err != nil && errors . IsAlreadyExists ( err ) {
glog . V ( 1 ) . Infof ( "glusterfs: service [%s] already exist in namespace [%s]" , service , namespace )
err = nil
}
if err != nil {
2016-11-14 14:16:09 +00:00
glog . Errorf ( "glusterfs: failed to create service: %v" , err )
return nil , nil , fmt . Errorf ( "error creating service: %v" , err )
2016-10-19 16:23:17 +00:00
}
return endpoint , service , nil
}
func ( d * glusterfsVolumeDeleter ) deleteEndpointService ( namespace string , epServiceName string ) ( err error ) {
2016-12-20 09:06:35 +00:00
kubeClient := d . plugin . host . GetKubeClient ( )
if kubeClient == nil {
return fmt . Errorf ( "glusterfs: failed to get kube client when deleting endpoint service" )
}
err = kubeClient . Core ( ) . Services ( namespace ) . Delete ( epServiceName , nil )
2016-10-19 16:23:17 +00:00
if err != nil {
2016-11-14 14:16:09 +00:00
glog . Errorf ( "glusterfs: error deleting service %s/%s: %v" , namespace , epServiceName , err )
return fmt . Errorf ( "error deleting service %s/%s: %v" , namespace , epServiceName , err )
2016-10-19 16:23:17 +00:00
}
2016-11-14 14:16:09 +00:00
glog . V ( 1 ) . Infof ( "glusterfs: service/endpoint %s/%s deleted successfully" , namespace , epServiceName )
2016-10-19 16:23:17 +00:00
return 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 ) {
2016-10-27 06:21:36 +00:00
secretMap , err := volutil . GetSecretForPV ( namespace , secretName , glusterfsPluginName , kubeClient )
2016-09-20 14:24:30 +00:00
if err != nil {
2016-11-14 14:16:09 +00:00
glog . Errorf ( "failed to get secret %s/%s: %v" , namespace , secretName , err )
return "" , fmt . Errorf ( "failed to get secret %s/%s: %v" , namespace , secretName , err )
2016-09-20 14:24:30 +00:00
}
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
}
2016-10-18 07:54:35 +00:00
// parseClassParameters parses StorageClass.Parameters
2017-01-31 09:01:55 +00:00
func parseClassParameters ( params map [ string ] string , kubeClient clientset . Interface ) ( * provisionerConfig , error ) {
var cfg provisionerConfig
2016-10-18 07:54:35 +00:00
var err error
2016-12-08 10:10:14 +00:00
cfg . gidMin = defaultGidMin
cfg . gidMax = defaultGidMax
2016-10-18 07:54:35 +00:00
authEnabled := true
2017-01-06 07:03:25 +00:00
parseVolumeType := ""
2016-10-18 07:54:35 +00:00
for k , v := range params {
switch dstrings . ToLower ( k ) {
case "resturl" :
cfg . url = v
case "restuser" :
cfg . user = v
case "restuserkey" :
cfg . userKey = v
case "secretname" :
cfg . secretName = v
case "secretnamespace" :
cfg . secretNamespace = v
2016-11-23 07:27:35 +00:00
case "clusterid" :
2016-12-05 08:06:10 +00:00
if len ( v ) != 0 {
cfg . clusterId = v
}
2016-10-18 07:54:35 +00:00
case "restauthenabled" :
authEnabled = dstrings . ToLower ( v ) == "true"
2016-12-02 01:16:23 +00:00
case "gidmin" :
parseGidMin , err := convertGid ( v )
if err != nil {
return nil , fmt . Errorf ( "glusterfs: invalid value %q for volume plugin %s" , k , glusterfsPluginName )
}
2016-12-08 10:10:14 +00:00
if parseGidMin < absoluteGidMin {
return nil , fmt . Errorf ( "glusterfs: gidMin must be >= %v" , absoluteGidMin )
}
if parseGidMin > absoluteGidMax {
return nil , fmt . Errorf ( "glusterfs: gidMin must be <= %v" , absoluteGidMax )
}
2016-12-02 01:16:23 +00:00
cfg . gidMin = parseGidMin
case "gidmax" :
parseGidMax , err := convertGid ( v )
if err != nil {
return nil , fmt . Errorf ( "glusterfs: invalid value %q for volume plugin %s" , k , glusterfsPluginName )
}
2016-12-08 10:10:14 +00:00
if parseGidMax < absoluteGidMin {
return nil , fmt . Errorf ( "glusterfs: gidMax must be >= %v" , absoluteGidMin )
}
if parseGidMax > absoluteGidMax {
return nil , fmt . Errorf ( "glusterfs: gidMax must be <= %v" , absoluteGidMax )
}
2016-12-02 01:16:23 +00:00
cfg . gidMax = parseGidMax
2017-01-06 07:03:25 +00:00
case "volumetype" :
parseVolumeType = v
2016-10-18 07:54:35 +00:00
default :
return nil , fmt . Errorf ( "glusterfs: invalid option %q for volume plugin %s" , k , glusterfsPluginName )
}
2016-09-20 14:24:30 +00:00
}
2016-10-18 07:54:35 +00:00
if len ( cfg . url ) == 0 {
return nil , fmt . Errorf ( "StorageClass for provisioner %s must contain 'resturl' parameter" , glusterfsPluginName )
2016-09-20 14:24:30 +00:00
}
2017-01-06 07:03:25 +00:00
if len ( parseVolumeType ) == 0 {
cfg . volumeType = gapi . VolumeDurabilityInfo { Type : gapi . DurabilityReplicate , Replicate : gapi . ReplicaDurability { Replica : replicaCount } }
} else {
parseVolumeTypeInfo := dstrings . Split ( parseVolumeType , ":" )
switch parseVolumeTypeInfo [ 0 ] {
case "replicate" :
if len ( parseVolumeTypeInfo ) >= 2 {
newReplicaCount , err := convertVolumeParam ( parseVolumeTypeInfo [ 1 ] )
if err != nil {
return nil , fmt . Errorf ( "error [%v] when parsing value %q of option '%s' for volume plugin %s." , err , parseVolumeTypeInfo [ 1 ] , "volumetype" , glusterfsPluginName )
}
cfg . volumeType = gapi . VolumeDurabilityInfo { Type : gapi . DurabilityReplicate , Replicate : gapi . ReplicaDurability { Replica : newReplicaCount } }
} else {
cfg . volumeType = gapi . VolumeDurabilityInfo { Type : gapi . DurabilityReplicate , Replicate : gapi . ReplicaDurability { Replica : replicaCount } }
}
case "disperse" :
if len ( parseVolumeTypeInfo ) >= 3 {
newDisperseData , err := convertVolumeParam ( parseVolumeTypeInfo [ 1 ] )
if err != nil {
return nil , fmt . Errorf ( "error [%v] when parsing value %q of option '%s' for volume plugin %s." , parseVolumeTypeInfo [ 1 ] , err , "volumetype" , glusterfsPluginName )
}
newDisperseRedundancy , err := convertVolumeParam ( parseVolumeTypeInfo [ 2 ] )
if err != nil {
return nil , fmt . Errorf ( "error [%v] when parsing value %q of option '%s' for volume plugin %s." , err , parseVolumeTypeInfo [ 2 ] , "volumetype" , glusterfsPluginName )
}
cfg . volumeType = gapi . VolumeDurabilityInfo { Type : gapi . DurabilityEC , Disperse : gapi . DisperseDurability { Data : newDisperseData , Redundancy : newDisperseRedundancy } }
} else {
return nil , fmt . Errorf ( "StorageClass for provisioner %q must have data:redundancy count set for disperse volumes in storage class option '%s'" , glusterfsPluginName , "volumetype" )
}
case "none" :
cfg . volumeType = gapi . VolumeDurabilityInfo { Type : gapi . DurabilityDistributeOnly }
default :
return nil , fmt . Errorf ( "error parsing value for option 'volumetype' for volume plugin %s" , glusterfsPluginName )
}
}
2016-10-18 07:54:35 +00:00
if ! authEnabled {
cfg . user = ""
cfg . secretName = ""
cfg . secretNamespace = ""
cfg . userKey = ""
cfg . secretValue = ""
}
if len ( cfg . secretName ) != 0 || len ( cfg . secretNamespace ) != 0 {
// secretName + Namespace has precedence over userKey
if len ( cfg . secretName ) != 0 && len ( cfg . secretNamespace ) != 0 {
cfg . secretValue , err = parseSecret ( cfg . secretNamespace , cfg . secretName , kubeClient )
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" , glusterfsPluginName )
}
} else {
cfg . secretValue = cfg . userKey
}
2016-12-02 01:16:23 +00:00
if cfg . gidMin > cfg . gidMax {
return nil , fmt . Errorf ( "StorageClass for provisioner %q must have gidMax value >= gidMin" , glusterfsPluginName )
}
2016-10-18 07:54:35 +00:00
return & cfg , nil
2016-09-20 14:24:30 +00:00
}