ScaleIO - API source code update

This commit tracks all human-generated code for API source updates.
This commit is contained in:
Vladimir Vivien 2017-10-13 22:57:37 -04:00
parent 7b588817ca
commit 3fb3cc7122
14 changed files with 455 additions and 154 deletions

View File

@ -410,14 +410,16 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
} }
}, },
func(sio *api.ScaleIOVolumeSource, c fuzz.Continue) { func(sio *api.ScaleIOVolumeSource, c fuzz.Continue) {
sio.ProtectionDomain = c.RandString() sio.StorageMode = c.RandString()
if sio.ProtectionDomain == "" { if sio.StorageMode == "" {
sio.ProtectionDomain = "default" sio.StorageMode = "ThinProvisioned"
} }
sio.StoragePool = c.RandString() sio.FSType = c.RandString()
if sio.StoragePool == "" { if sio.FSType == "" {
sio.StoragePool = "default" sio.FSType = "xfs"
} }
},
func(sio *api.ScaleIOPersistentVolumeSource, c fuzz.Continue) {
sio.StorageMode = c.RandString() sio.StorageMode = c.RandString()
if sio.StorageMode == "" { if sio.StorageMode == "" {
sio.StorageMode = "ThinProvisioned" sio.StorageMode = "ThinProvisioned"

View File

@ -76,9 +76,15 @@ func VisitPVSecretNames(pv *api.PersistentVolume, visitor Visitor) bool {
} }
} }
case source.ScaleIO != nil: case source.ScaleIO != nil:
if source.ScaleIO.SecretRef != nil && !visitor(getClaimRefNamespace(pv), source.ScaleIO.SecretRef.Name) { if source.ScaleIO.SecretRef != nil {
ns := getClaimRefNamespace(pv)
if source.ScaleIO.SecretRef != nil && len(source.ScaleIO.SecretRef.Namespace) > 0 {
ns = source.ScaleIO.SecretRef.Namespace
}
if !visitor(ns, source.ScaleIO.SecretRef.Name) {
return false return false
} }
}
case source.ISCSI != nil: case source.ISCSI != nil:
if source.ISCSI.SecretRef != nil && !visitor(getClaimRefNamespace(pv), source.ISCSI.SecretRef.Name) { if source.ISCSI.SecretRef != nil && !visitor(getClaimRefNamespace(pv), source.ISCSI.SecretRef.Name) {
return false return false

View File

@ -78,9 +78,16 @@ func TestPVSecrets(t *testing.T) {
{Spec: api.PersistentVolumeSpec{ {Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"}, ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{ PersistentVolumeSource: api.PersistentVolumeSource{
ScaleIO: &api.ScaleIOVolumeSource{ ScaleIO: &api.ScaleIOPersistentVolumeSource{
SecretRef: &api.LocalObjectReference{ SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.ScaleIO.SecretRef"}}}}}, Name: "Spec.PersistentVolumeSource.ScaleIO.SecretRef"}}}}},
{Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{
ScaleIO: &api.ScaleIOPersistentVolumeSource{
SecretRef: &api.SecretReference{
Name: "Spec.PersistentVolumeSource.ScaleIO.SecretRef",
Namespace: "scaleions"}}}}},
{Spec: api.PersistentVolumeSpec{ {Spec: api.PersistentVolumeSpec{
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"}, ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
PersistentVolumeSource: api.PersistentVolumeSource{ PersistentVolumeSource: api.PersistentVolumeSource{
@ -150,6 +157,7 @@ func TestPVSecrets(t *testing.T) {
"claimrefns/Spec.PersistentVolumeSource.RBD.SecretRef", "claimrefns/Spec.PersistentVolumeSource.RBD.SecretRef",
"rbdns/Spec.PersistentVolumeSource.RBD.SecretRef", "rbdns/Spec.PersistentVolumeSource.RBD.SecretRef",
"claimrefns/Spec.PersistentVolumeSource.ScaleIO.SecretRef", "claimrefns/Spec.PersistentVolumeSource.ScaleIO.SecretRef",
"scaleions/Spec.PersistentVolumeSource.ScaleIO.SecretRef",
"claimrefns/Spec.PersistentVolumeSource.ISCSI.SecretRef", "claimrefns/Spec.PersistentVolumeSource.ISCSI.SecretRef",
"storageosns/Spec.PersistentVolumeSource.StorageOS.SecretRef", "storageosns/Spec.PersistentVolumeSource.StorageOS.SecretRef",
) )

View File

@ -383,7 +383,7 @@ type PersistentVolumeSource struct {
PortworxVolume *PortworxVolumeSource PortworxVolume *PortworxVolumeSource
// ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. // ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.
// +optional // +optional
ScaleIO *ScaleIOVolumeSource ScaleIO *ScaleIOPersistentVolumeSource
// Local represents directly-attached storage with node affinity // Local represents directly-attached storage with node affinity
// +optional // +optional
Local *LocalVolumeSource Local *LocalVolumeSource
@ -1285,13 +1285,13 @@ type ScaleIOVolumeSource struct {
// Flag to enable/disable SSL communication with Gateway, default false // Flag to enable/disable SSL communication with Gateway, default false
// +optional // +optional
SSLEnabled bool SSLEnabled bool
// The name of the Protection Domain for the configured storage (defaults to "default"). // The name of the ScaleIO Protection Domain for the configured storage.
// +optional // +optional
ProtectionDomain string ProtectionDomain string
// The Storage Pool associated with the protection domain (defaults to "default"). // The ScaleIO Storage Pool associated with the protection domain.
// +optional // +optional
StoragePool string StoragePool string
// Indicates whether the storage for a volume should be thick or thin (defaults to "thin"). // Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.
// +optional // +optional
StorageMode string StorageMode string
// The name of a volume already created in the ScaleIO system // The name of a volume already created in the ScaleIO system
@ -1308,6 +1308,42 @@ type ScaleIOVolumeSource struct {
ReadOnly bool ReadOnly bool
} }
// ScaleIOPersistentVolumeSource represents a persistent ScaleIO volume that can be defined
// by a an admin via a storage class, for instance.
type ScaleIOPersistentVolumeSource struct {
// The host address of the ScaleIO API Gateway.
Gateway string
// The name of the storage system as configured in ScaleIO.
System string
// SecretRef references to the secret for ScaleIO user and other
// sensitive information. If this is not provided, Login operation will fail.
SecretRef *SecretReference
// Flag to enable/disable SSL communication with Gateway, default false
// +optional
SSLEnabled bool
// The name of the ScaleIO Protection Domain for the configured storage.
// +optional
ProtectionDomain string
// The ScaleIO Storage Pool associated with the protection domain.
// +optional
StoragePool string
// Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.
// +optional
StorageMode string
// The name of a volume created in the ScaleIO system
// that is associated with this volume source.
VolumeName string
// Filesystem type to mount.
// Must be a filesystem type supported by the host operating system.
// Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
// +optional
FSType string
// Defaults to false (read/write). ReadOnly here will force
// the ReadOnly setting in VolumeMounts.
// +optional
ReadOnly bool
}
// Represents a StorageOS persistent volume resource. // Represents a StorageOS persistent volume resource.
type StorageOSVolumeSource struct { type StorageOSVolumeSource struct {
// VolumeName is the human-readable name of the StorageOS volume. Volume // VolumeName is the human-readable name of the StorageOS volume. Volume

View File

@ -381,12 +381,15 @@ func SetDefaults_RBDPersistentVolumeSource(obj *v1.RBDPersistentVolumeSource) {
} }
func SetDefaults_ScaleIOVolumeSource(obj *v1.ScaleIOVolumeSource) { func SetDefaults_ScaleIOVolumeSource(obj *v1.ScaleIOVolumeSource) {
if obj.ProtectionDomain == "" { if obj.StorageMode == "" {
obj.ProtectionDomain = "default" obj.StorageMode = "ThinProvisioned"
} }
if obj.StoragePool == "" { if obj.FSType == "" {
obj.StoragePool = "default" obj.FSType = "xfs"
} }
}
func SetDefaults_ScaleIOPersistentVolumeSource(obj *v1.ScaleIOPersistentVolumeSource) {
if obj.StorageMode == "" { if obj.StorageMode == "" {
obj.StorageMode = "ThinProvisioned" obj.StorageMode = "ThinProvisioned"
} }

View File

@ -1245,6 +1245,20 @@ func validateScaleIOVolumeSource(sio *api.ScaleIOVolumeSource, fldPath *field.Pa
return allErrs return allErrs
} }
func validateScaleIOPersistentVolumeSource(sio *api.ScaleIOPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if sio.Gateway == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("gateway"), ""))
}
if sio.System == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("system"), ""))
}
if sio.VolumeName == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("volumeName"), ""))
}
return allErrs
}
func validateLocalVolumeSource(ls *api.LocalVolumeSource, fldPath *field.Path) field.ErrorList { func validateLocalVolumeSource(ls *api.LocalVolumeSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if ls.Path == "" { if ls.Path == "" {
@ -1489,7 +1503,7 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList {
allErrs = append(allErrs, field.Forbidden(specPath.Child("scaleIO"), "may not specify more than 1 volume type")) allErrs = append(allErrs, field.Forbidden(specPath.Child("scaleIO"), "may not specify more than 1 volume type"))
} else { } else {
numVolumes++ numVolumes++
allErrs = append(allErrs, validateScaleIOVolumeSource(pv.Spec.ScaleIO, specPath.Child("scaleIO"))...) allErrs = append(allErrs, validateScaleIOPersistentVolumeSource(pv.Spec.ScaleIO, specPath.Child("scaleIO"))...)
} }
} }
if pv.Spec.Local != nil { if pv.Spec.Local != nil {

View File

@ -970,6 +970,26 @@ func printScaleIOVolumeSource(sio *api.ScaleIOVolumeSource, w PrefixWriter) {
sio.Gateway, sio.System, sio.ProtectionDomain, sio.StoragePool, sio.StorageMode, sio.VolumeName, sio.FSType, sio.ReadOnly) sio.Gateway, sio.System, sio.ProtectionDomain, sio.StoragePool, sio.StorageMode, sio.VolumeName, sio.FSType, sio.ReadOnly)
} }
func printScaleIOPersistentVolumeSource(sio *api.ScaleIOPersistentVolumeSource, w PrefixWriter) {
var secretNS, secretName string
if sio.SecretRef != nil {
secretName = sio.SecretRef.Name
secretNS = sio.SecretRef.Namespace
}
w.Write(LEVEL_2, "Type:\tScaleIO (a persistent volume backed by a block device in ScaleIO)\n"+
" Gateway:\t%v\n"+
" System:\t%v\n"+
" Protection Domain:\t%v\n"+
" Storage Pool:\t%v\n"+
" Storage Mode:\t%v\n"+
" VolumeName:\t%v\n"+
" SecretName:\t%v\n"+
" SecretNamespace:\t%v\n"+
" FSType:\t%v\n"+
" ReadOnly:\t%v\n",
sio.Gateway, sio.System, sio.ProtectionDomain, sio.StoragePool, sio.StorageMode, sio.VolumeName, secretName, secretNS, sio.FSType, sio.ReadOnly)
}
func printLocalVolumeSource(ls *api.LocalVolumeSource, w PrefixWriter) { func printLocalVolumeSource(ls *api.LocalVolumeSource, w PrefixWriter) {
w.Write(LEVEL_2, "Type:\tLocalVolume (a persistent volume backed by local storage on a node)\n"+ w.Write(LEVEL_2, "Type:\tLocalVolume (a persistent volume backed by local storage on a node)\n"+
" Path:\t%v\n", " Path:\t%v\n",
@ -1135,7 +1155,7 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (
case pv.Spec.PortworxVolume != nil: case pv.Spec.PortworxVolume != nil:
printPortworxVolumeSource(pv.Spec.PortworxVolume, w) printPortworxVolumeSource(pv.Spec.PortworxVolume, w)
case pv.Spec.ScaleIO != nil: case pv.Spec.ScaleIO != nil:
printScaleIOVolumeSource(pv.Spec.ScaleIO, w) printScaleIOPersistentVolumeSource(pv.Spec.ScaleIO, w)
case pv.Spec.Local != nil: case pv.Spec.Local != nil:
printLocalVolumeSource(pv.Spec.Local, w) printLocalVolumeSource(pv.Spec.Local, w)
case pv.Spec.CephFS != nil: case pv.Spec.CephFS != nil:

View File

@ -37,7 +37,7 @@ var (
confKey.sslEnabled: "false", confKey.sslEnabled: "false",
confKey.system: "scaleio", confKey.system: "scaleio",
confKey.volumeName: "sio-0001", confKey.volumeName: "sio-0001",
confKey.secretRef: "sio-secret", confKey.secretName: "sio-secret",
confKey.username: "c2lvdXNlcgo=", // siouser confKey.username: "c2lvdXNlcgo=", // siouser
confKey.password: "c2lvcGFzc3dvcmQK", // siopassword confKey.password: "c2lvcGFzc3dvcmQK", // siopassword
} }

View File

@ -60,12 +60,11 @@ func (p *sioPlugin) GetPluginName() string {
} }
func (p *sioPlugin) GetVolumeName(spec *volume.Spec) (string, error) { func (p *sioPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
source, err := getVolumeSourceFromSpec(spec) attribs, err := getVolumeSourceAttribs(spec)
if err != nil { if err != nil {
return "", err return "", err
} }
return attribs.volName, nil
return source.VolumeName, nil
} }
func (p *sioPlugin) CanSupport(spec *volume.Spec) bool { func (p *sioPlugin) CanSupport(spec *volume.Spec) bool {
@ -81,29 +80,33 @@ func (p *sioPlugin) NewMounter(
spec *volume.Spec, spec *volume.Spec,
pod *api.Pod, pod *api.Pod,
_ volume.VolumeOptions) (volume.Mounter, error) { _ volume.VolumeOptions) (volume.Mounter, error) {
sioSource, err := getVolumeSourceFromSpec(spec)
// extract source info from either ScaleIOVolumeSource or ScaleIOPersistentVolumeSource type
attribs, err := getVolumeSourceAttribs(spec)
if err != nil { if err != nil {
glog.Error(log("failed to extract ScaleIOVolumeSource from spec: %v", err)) return nil, errors.New(log("mounter failed to extract volume attributes from spec: %v", err))
return nil, err }
secretName, secretNS, err := getSecretAndNamespaceFromSpec(spec, pod)
if err != nil {
return nil, errors.New(log("failed to get secret name or secretNamespace: %v", err))
} }
return &sioVolume{ return &sioVolume{
pod: pod, pod: pod,
spec: spec, spec: spec,
source: sioSource, secretName: secretName,
namespace: pod.Namespace, secretNamespace: secretNS,
volSpecName: spec.Name(), volSpecName: spec.Name(),
volName: sioSource.VolumeName, volName: attribs.volName,
podUID: pod.UID, podUID: pod.UID,
readOnly: sioSource.ReadOnly, readOnly: attribs.readOnly,
fsType: sioSource.FSType, fsType: attribs.fsType,
plugin: p, plugin: p,
}, nil }, nil
} }
// NewUnmounter creates a representation of the volume to unmount // NewUnmounter creates a representation of the volume to unmount
// The specName param can be used to carry the namespace value (if needed) using format:
// specName = [<namespace>nsSep]<somevalue> where the specname is pre-pended with the namespace
func (p *sioPlugin) NewUnmounter(specName string, podUID types.UID) (volume.Unmounter, error) { func (p *sioPlugin) NewUnmounter(specName string, podUID types.UID) (volume.Unmounter, error) {
glog.V(4).Info(log("Unmounter for %s", specName)) glog.V(4).Info(log("Unmounter for %s", specName))
@ -156,22 +159,25 @@ func (p *sioPlugin) GetAccessModes() []api.PersistentVolumeAccessMode {
var _ volume.DeletableVolumePlugin = &sioPlugin{} var _ volume.DeletableVolumePlugin = &sioPlugin{}
func (p *sioPlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) { func (p *sioPlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) {
sioSource, err := getVolumeSourceFromSpec(spec) attribs, err := getVolumeSourceAttribs(spec)
if err != nil { if err != nil {
glog.Error(log("deleter failed to extract source from spec: %v", err)) glog.Error(log("deleter failed to extract volume attributes from spec: %v", err))
return nil, err return nil, err
} }
namespace := spec.PersistentVolume.Spec.ClaimRef.Namespace secretName, secretNS, err := getSecretAndNamespaceFromSpec(spec, nil)
if err != nil {
return nil, errors.New(log("failed to get secret name or secretNamespace: %v", err))
}
return &sioVolume{ return &sioVolume{
spec: spec, spec: spec,
source: sioSource, secretName: secretName,
namespace: namespace, secretNamespace: secretNS,
volSpecName: spec.Name(), volSpecName: spec.Name(),
volName: sioSource.VolumeName, volName: attribs.volName,
plugin: p, plugin: p,
readOnly: sioSource.ReadOnly, readOnly: attribs.readOnly,
}, nil }, nil
} }
@ -189,13 +195,26 @@ func (p *sioPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisi
return nil, errors.New("option parameters missing") return nil, errors.New("option parameters missing")
} }
namespace := options.PVC.Namespace // Supports ref of name of secret a couple of ways:
// options.Parameters["secretRef"] for backward compat, or
// options.Parameters["secretName"]
secretName := configData[confKey.secretName]
if secretName == "" {
secretName = configData["secretName"]
configData[confKey.secretName] = secretName
}
secretNS := configData[confKey.secretNamespace]
if secretNS == "" {
secretNS = options.PVC.Namespace
}
return &sioVolume{ return &sioVolume{
configData: configData, configData: configData,
plugin: p, plugin: p,
options: options, options: options,
namespace: namespace, secretName: secretName,
secretNamespace: secretNS,
volSpecName: options.PVName, volSpecName: options.PVName,
}, nil }, nil
} }

View File

@ -31,11 +31,17 @@ import (
volutil "k8s.io/kubernetes/pkg/volume/util" volutil "k8s.io/kubernetes/pkg/volume/util"
) )
type volSourceAttribs struct {
volName,
fsType string
readOnly bool
}
var ( var (
confKey = struct { confKey = struct {
gateway, gateway,
sslEnabled, sslEnabled,
secretRef, secretName,
system, system,
protectionDomain, protectionDomain,
storagePool, storagePool,
@ -47,12 +53,13 @@ var (
readOnly, readOnly,
username, username,
password, password,
namespace, secretNamespace,
sdcGuid string sdcGuid string
}{ }{
gateway: "gateway", gateway: "gateway",
sslEnabled: "sslEnabled", sslEnabled: "sslEnabled",
secretRef: "secretRef", secretName: "secretRef",
secretNamespace: "secretNamespace",
system: "system", system: "system",
protectionDomain: "protectionDomain", protectionDomain: "protectionDomain",
storagePool: "storagePool", storagePool: "storagePool",
@ -64,7 +71,6 @@ var (
readOnly: "readOnly", readOnly: "readOnly",
username: "username", username: "username",
password: "password", password: "password",
namespace: "namespace",
sdcGuid: "sdcGuid", sdcGuid: "sdcGuid",
} }
sdcGuidLabelName = "scaleio.sdcGuid" sdcGuidLabelName = "scaleio.sdcGuid"
@ -79,15 +85,11 @@ var (
protectionDomainNotProvidedErr = errors.New("ScaleIO protection domain not provided") protectionDomainNotProvidedErr = errors.New("ScaleIO protection domain not provided")
) )
// mapScaleIOVolumeSource maps attributes from a ScaleIOVolumeSource to config // mapVolumeSpec maps attributes from either ScaleIOVolumeSource or ScaleIOPersistentVolumeSource to config
func mapVolumeSource(config map[string]string, source *api.ScaleIOVolumeSource) { func mapVolumeSpec(config map[string]string, spec *volume.Spec) {
if source, err := getScaleIOPersistentVolumeSourceFromSpec(spec); err == nil {
config[confKey.gateway] = source.Gateway config[confKey.gateway] = source.Gateway
config[confKey.secretRef] = func() string {
if source.SecretRef != nil {
return string(source.SecretRef.Name)
}
return ""
}()
config[confKey.system] = source.System config[confKey.system] = source.System
config[confKey.volumeName] = source.VolumeName config[confKey.volumeName] = source.VolumeName
config[confKey.sslEnabled] = strconv.FormatBool(source.SSLEnabled) config[confKey.sslEnabled] = strconv.FormatBool(source.SSLEnabled)
@ -96,6 +98,19 @@ func mapVolumeSource(config map[string]string, source *api.ScaleIOVolumeSource)
config[confKey.storageMode] = source.StorageMode config[confKey.storageMode] = source.StorageMode
config[confKey.fsType] = source.FSType config[confKey.fsType] = source.FSType
config[confKey.readOnly] = strconv.FormatBool(source.ReadOnly) config[confKey.readOnly] = strconv.FormatBool(source.ReadOnly)
}
if source, err := getScaleIOVolumeSourceFromSpec(spec); err == nil {
config[confKey.gateway] = source.Gateway
config[confKey.system] = source.System
config[confKey.volumeName] = source.VolumeName
config[confKey.sslEnabled] = strconv.FormatBool(source.SSLEnabled)
config[confKey.protectionDomain] = source.ProtectionDomain
config[confKey.storagePool] = source.StoragePool
config[confKey.storageMode] = source.StorageMode
config[confKey.fsType] = source.FSType
config[confKey.readOnly] = strconv.FormatBool(source.ReadOnly)
}
//optionals //optionals
applyConfigDefaults(config) applyConfigDefaults(config)
@ -105,7 +120,7 @@ func validateConfigs(config map[string]string) error {
if config[confKey.gateway] == "" { if config[confKey.gateway] == "" {
return gatewayNotProvidedErr return gatewayNotProvidedErr
} }
if config[confKey.secretRef] == "" { if config[confKey.secretName] == "" {
return secretRefNotProvidedErr return secretRefNotProvidedErr
} }
if config[confKey.system] == "" { if config[confKey.system] == "" {
@ -202,7 +217,7 @@ func saveConfig(configName string, data map[string]string) error {
// attachSecret loads secret object and attaches to configData // attachSecret loads secret object and attaches to configData
func attachSecret(plug *sioPlugin, namespace string, configData map[string]string) error { func attachSecret(plug *sioPlugin, namespace string, configData map[string]string) error {
// load secret // load secret
secretRefName := configData[confKey.secretRef] secretRefName := configData[confKey.secretName]
kubeClient := plug.host.GetKubeClient() kubeClient := plug.host.GetKubeClient()
secretMap, err := volutil.GetSecretForPV(namespace, secretRefName, sioPluginName, kubeClient) secretMap, err := volutil.GetSecretForPV(namespace, secretRefName, sioPluginName, kubeClient)
if err != nil { if err != nil {
@ -244,8 +259,8 @@ func getSdcGuidLabel(plug *sioPlugin) (string, error) {
return label, nil return label, nil
} }
// getVolumeSourceFromSpec safely extracts ScaleIOVolumeSource from spec // getVolumeSourceFromSpec safely extracts ScaleIOVolumeSource or ScaleIOPersistentVolumeSource from spec
func getVolumeSourceFromSpec(spec *volume.Spec) (*api.ScaleIOVolumeSource, error) { func getVolumeSourceFromSpec(spec *volume.Spec) (interface{}, error) {
if spec.Volume != nil && spec.Volume.ScaleIO != nil { if spec.Volume != nil && spec.Volume.ScaleIO != nil {
return spec.Volume.ScaleIO, nil return spec.Volume.ScaleIO, nil
} }
@ -257,6 +272,66 @@ func getVolumeSourceFromSpec(spec *volume.Spec) (*api.ScaleIOVolumeSource, error
return nil, fmt.Errorf("ScaleIO not defined in spec") return nil, fmt.Errorf("ScaleIO not defined in spec")
} }
func getVolumeSourceAttribs(spec *volume.Spec) (*volSourceAttribs, error) {
attribs := new(volSourceAttribs)
if pvSource, err := getScaleIOPersistentVolumeSourceFromSpec(spec); err == nil {
attribs.volName = pvSource.VolumeName
attribs.fsType = pvSource.FSType
attribs.readOnly = pvSource.ReadOnly
} else if pSource, err := getScaleIOVolumeSourceFromSpec(spec); err == nil {
attribs.volName = pSource.VolumeName
attribs.fsType = pSource.FSType
attribs.readOnly = pSource.ReadOnly
} else {
msg := log("failed to get ScaleIOVolumeSource or ScaleIOPersistentVolumeSource from spec")
glog.Error(msg)
return nil, errors.New(msg)
}
return attribs, nil
}
func getScaleIOPersistentVolumeSourceFromSpec(spec *volume.Spec) (*api.ScaleIOPersistentVolumeSource, error) {
source, err := getVolumeSourceFromSpec(spec)
if err != nil {
return nil, err
}
if val, ok := source.(*api.ScaleIOPersistentVolumeSource); ok {
return val, nil
}
return nil, fmt.Errorf("spec is not a valid ScaleIOPersistentVolume type")
}
func getScaleIOVolumeSourceFromSpec(spec *volume.Spec) (*api.ScaleIOVolumeSource, error) {
source, err := getVolumeSourceFromSpec(spec)
if err != nil {
return nil, err
}
if val, ok := source.(*api.ScaleIOVolumeSource); ok {
return val, nil
}
return nil, fmt.Errorf("spec is not a valid ScaleIOVolume type")
}
func getSecretAndNamespaceFromSpec(spec *volume.Spec, pod *api.Pod) (secretName string, secretNS string, err error) {
if source, err := getScaleIOVolumeSourceFromSpec(spec); err == nil {
secretName = source.SecretRef.Name
if pod != nil {
secretNS = pod.Namespace
}
} else if source, err := getScaleIOPersistentVolumeSourceFromSpec(spec); err == nil {
if source.SecretRef != nil {
secretName = source.SecretRef.Name
secretNS = source.SecretRef.Namespace
if secretNS == "" && pod != nil {
secretNS = pod.Namespace
}
}
} else {
return "", "", errors.New("failed to get ScaleIOVolumeSource or ScaleIOPersistentVolumeSource")
}
return secretName, secretNS, nil
}
func log(msg string, parts ...interface{}) string { func log(msg string, parts ...interface{}) string {
return fmt.Sprintf(fmt.Sprintf("scaleio: %s", msg), parts...) return fmt.Sprintf(fmt.Sprintf("scaleio: %s", msg), parts...)
} }

View File

@ -25,6 +25,7 @@ import (
api "k8s.io/api/core/v1" api "k8s.io/api/core/v1"
utiltesting "k8s.io/client-go/util/testing" utiltesting "k8s.io/client-go/util/testing"
"k8s.io/kubernetes/pkg/volume"
) )
var ( var (
@ -48,7 +49,7 @@ var (
confKey.gateway: "http://sio/", confKey.gateway: "http://sio/",
confKey.volSpecName: testSioVolName, confKey.volSpecName: testSioVolName,
confKey.volumeName: "sio-vol", confKey.volumeName: "sio-vol",
confKey.secretRef: "sio-secret", confKey.secretName: "sio-secret",
confKey.protectionDomain: "defaultPD", confKey.protectionDomain: "defaultPD",
confKey.storagePool: "deraultSP", confKey.storagePool: "deraultSP",
confKey.fsType: "xfs", confKey.fsType: "xfs",
@ -60,7 +61,7 @@ var (
func TestUtilMapVolumeSource(t *testing.T) { func TestUtilMapVolumeSource(t *testing.T) {
data := make(map[string]string) data := make(map[string]string)
mapVolumeSource(data, vol.VolumeSource.ScaleIO) mapVolumeSpec(data, volume.NewSpecFromVolume(vol))
if data[confKey.gateway] != "http://test.scaleio:1111" { if data[confKey.gateway] != "http://test.scaleio:1111" {
t.Error("Unexpected gateway value") t.Error("Unexpected gateway value")
} }
@ -79,9 +80,6 @@ func TestUtilMapVolumeSource(t *testing.T) {
if data[confKey.fsType] != "ext4" { if data[confKey.fsType] != "ext4" {
t.Error("Unexpected fstype value") t.Error("Unexpected fstype value")
} }
if data[confKey.secretRef] != "test-secret" {
t.Error("Unexpected secret ref value")
}
if data[confKey.sslEnabled] != "false" { if data[confKey.sslEnabled] != "false" {
t.Error("Unexpected sslEnabled value") t.Error("Unexpected sslEnabled value")
} }
@ -92,7 +90,7 @@ func TestUtilMapVolumeSource(t *testing.T) {
func TestUtilValidateConfigs(t *testing.T) { func TestUtilValidateConfigs(t *testing.T) {
data := map[string]string{ data := map[string]string{
confKey.secretRef: "sio-secret", confKey.secretName: "sio-secret",
confKey.system: "sio", confKey.system: "sio",
} }
if err := validateConfigs(data); err != gatewayNotProvidedErr { if err := validateConfigs(data); err != gatewayNotProvidedErr {
@ -105,7 +103,7 @@ func TestUtilApplyConfigDefaults(t *testing.T) {
confKey.system: "sio", confKey.system: "sio",
confKey.gateway: "http://sio/", confKey.gateway: "http://sio/",
confKey.volumeName: "sio-vol", confKey.volumeName: "sio-vol",
confKey.secretRef: "test-secret", confKey.secretName: "test-secret",
} }
applyConfigDefaults(data) applyConfigDefaults(data)
@ -130,7 +128,7 @@ func TestUtilApplyConfigDefaults(t *testing.T) {
if data[confKey.storageMode] != "ThinProvisioned" { if data[confKey.storageMode] != "ThinProvisioned" {
t.Error("Unexpected storage mode value") t.Error("Unexpected storage mode value")
} }
if data[confKey.secretRef] != "test-secret" { if data[confKey.secretName] != "test-secret" {
t.Error("Unexpected secret ref value") t.Error("Unexpected secret ref value")
} }
if data[confKey.sslEnabled] != "false" { if data[confKey.sslEnabled] != "false" {
@ -157,7 +155,7 @@ func TestUtilSaveConfig(t *testing.T) {
config := path.Join(tmpDir, testConfigFile) config := path.Join(tmpDir, testConfigFile)
data := map[string]string{ data := map[string]string{
confKey.gateway: "https://test-gateway/", confKey.gateway: "https://test-gateway/",
confKey.secretRef: "sio-secret", confKey.secretName: "sio-secret",
confKey.sslEnabled: "false", confKey.sslEnabled: "false",
} }
if err := saveConfig(config, data); err != nil { if err := saveConfig(config, data); err != nil {
@ -178,7 +176,7 @@ func TestUtilSaveConfig(t *testing.T) {
} }
func TestUtilAttachSecret(t *testing.T) { func TestUtilAttachSecret(t *testing.T) {
plugMgr, tmpDir := newPluginMgr(t) plugMgr, tmpDir := newPluginMgr(t, makeScaleIOSecret(testSecret, testns))
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plug, err := plugMgr.FindPluginByName(sioPluginName) plug, err := plugMgr.FindPluginByName(sioPluginName)

View File

@ -42,8 +42,8 @@ type sioVolume struct {
pod *api.Pod pod *api.Pod
podUID types.UID podUID types.UID
spec *volume.Spec spec *volume.Spec
source *api.ScaleIOVolumeSource secretName string
namespace string secretNamespace string
volSpecName string volSpecName string
volName string volName string
readOnly bool readOnly bool
@ -59,7 +59,6 @@ type sioVolume struct {
var _ volume.Volume = &sioVolume{} var _ volume.Volume = &sioVolume{}
// GetPath returns the path where the volume will be mounted. // GetPath returns the path where the volume will be mounted.
// The volumeName is prefixed with the pod's namespace a <pod.Namespace>-<volumeName>
func (v *sioVolume) GetPath() string { func (v *sioVolume) GetPath() string {
return v.plugin.host.GetPodVolumeDir( return v.plugin.host.GetPodVolumeDir(
v.podUID, v.podUID,
@ -128,11 +127,11 @@ func (v *sioVolume) SetUpAt(dir string, fsGroup *int64) error {
switch { switch {
default: default:
options = append(options, "rw") options = append(options, "rw")
case isROM && !v.source.ReadOnly: case isROM && !v.readOnly:
options = append(options, "rw") options = append(options, "rw")
case isROM: case isROM:
options = append(options, "ro") options = append(options, "ro")
case v.source.ReadOnly: case v.readOnly:
options = append(options, "ro") options = append(options, "ro")
} }
@ -327,10 +326,10 @@ func (v *sioVolume) Provision() (*api.PersistentVolume, error) {
), ),
}, },
PersistentVolumeSource: api.PersistentVolumeSource{ PersistentVolumeSource: api.PersistentVolumeSource{
ScaleIO: &api.ScaleIOVolumeSource{ ScaleIO: &api.ScaleIOPersistentVolumeSource{
Gateway: v.configData[confKey.gateway], Gateway: v.configData[confKey.gateway],
SSLEnabled: sslEnabled, SSLEnabled: sslEnabled,
SecretRef: &api.LocalObjectReference{Name: v.configData[confKey.secretRef]}, SecretRef: &api.SecretReference{Name: v.secretName, Namespace: v.secretNamespace},
System: v.configData[confKey.system], System: v.configData[confKey.system],
ProtectionDomain: v.configData[confKey.protectionDomain], ProtectionDomain: v.configData[confKey.protectionDomain],
StoragePool: v.configData[confKey.storagePool], StoragePool: v.configData[confKey.storagePool],
@ -366,13 +365,17 @@ func (v *sioVolume) setSioMgr() error {
glog.V(4).Info(log("previous config file not found, creating new one")) glog.V(4).Info(log("previous config file not found, creating new one"))
// prepare config data // prepare config data
configData = make(map[string]string) configData = make(map[string]string)
mapVolumeSource(configData, v.source) mapVolumeSpec(configData, v.spec)
// additional config data
configData[confKey.secretNamespace] = v.secretNamespace
configData[confKey.secretName] = v.secretName
configData[confKey.volSpecName] = v.volSpecName
if err := validateConfigs(configData); err != nil { if err := validateConfigs(configData); err != nil {
glog.Error(log("config setup failed: %s", err)) glog.Error(log("config setup failed: %s", err))
return err return err
} }
configData[confKey.namespace] = v.namespace
configData[confKey.volSpecName] = v.volSpecName
// persist config // persist config
if err := saveConfig(configName, configData); err != nil { if err := saveConfig(configName, configData); err != nil {
@ -381,7 +384,7 @@ func (v *sioVolume) setSioMgr() error {
} }
} }
// merge in secret // merge in secret
if err := attachSecret(v.plugin, v.namespace, configData); err != nil { if err := attachSecret(v.plugin, v.secretNamespace, configData); err != nil {
glog.Error(log("failed to load secret: %v", err)) glog.Error(log("failed to load secret: %v", err))
return err return err
} }
@ -414,12 +417,13 @@ func (v *sioVolume) resetSioMgr() error {
glog.Error(log("failed to load config data: %v", err)) glog.Error(log("failed to load config data: %v", err))
return err return err
} }
v.namespace = configData[confKey.namespace] v.secretName = configData[confKey.secretName]
v.secretNamespace = configData[confKey.secretNamespace]
v.volName = configData[confKey.volumeName] v.volName = configData[confKey.volumeName]
v.volSpecName = configData[confKey.volSpecName] v.volSpecName = configData[confKey.volSpecName]
// attach secret // attach secret
if err := attachSecret(v.plugin, v.namespace, configData); err != nil { if err := attachSecret(v.plugin, v.secretNamespace, configData); err != nil {
glog.Error(log("failed to load secret: %v", err)) glog.Error(log("failed to load secret: %v", err))
return err return err
} }
@ -446,21 +450,22 @@ func (v *sioVolume) resetSioMgr() error {
func (v *sioVolume) setSioMgrFromConfig() error { func (v *sioVolume) setSioMgrFromConfig() error {
glog.V(4).Info(log("setting scaleio mgr from available config")) glog.V(4).Info(log("setting scaleio mgr from available config"))
if v.sioMgr == nil { if v.sioMgr == nil {
configData := v.configData applyConfigDefaults(v.configData)
applyConfigDefaults(configData)
if err := validateConfigs(configData); err != nil { v.configData[confKey.volSpecName] = v.volSpecName
if err := validateConfigs(v.configData); err != nil {
glog.Error(log("config data setup failed: %s", err)) glog.Error(log("config data setup failed: %s", err))
return err return err
} }
configData[confKey.namespace] = v.namespace
configData[confKey.volSpecName] = v.volSpecName
// copy config and attach secret // copy config and attach secret
data := map[string]string{} data := map[string]string{}
for k, v := range configData { for k, v := range v.configData {
data[k] = v data[k] = v
} }
if err := attachSecret(v.plugin, v.namespace, data); err != nil {
if err := attachSecret(v.plugin, v.secretNamespace, data); err != nil {
glog.Error(log("failed to load secret: %v", err)) glog.Error(log("failed to load secret: %v", err))
return err return err
} }
@ -483,16 +488,20 @@ func (v *sioVolume) setSioMgrFromSpec() error {
if v.sioMgr == nil { if v.sioMgr == nil {
// get config data form spec volume source // get config data form spec volume source
configData := map[string]string{} configData := map[string]string{}
mapVolumeSource(configData, v.source) mapVolumeSpec(configData, v.spec)
// additional config
configData[confKey.secretNamespace] = v.secretNamespace
configData[confKey.secretName] = v.secretName
configData[confKey.volSpecName] = v.volSpecName
if err := validateConfigs(configData); err != nil { if err := validateConfigs(configData); err != nil {
glog.Error(log("config setup failed: %s", err)) glog.Error(log("config setup failed: %s", err))
return err return err
} }
configData[confKey.namespace] = v.namespace
configData[confKey.volSpecName] = v.volSpecName
// attach secret object to config data // attach secret object to config data
if err := attachSecret(v.plugin, v.namespace, configData); err != nil { if err := attachSecret(v.plugin, v.secretNamespace, configData); err != nil {
glog.Error(log("failed to load secret: %v", err)) glog.Error(log("failed to load secret: %v", err))
return err return err
} }

View File

@ -27,6 +27,7 @@ import (
api "k8s.io/api/core/v1" api "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
fakeclient "k8s.io/client-go/kubernetes/fake" fakeclient "k8s.io/client-go/kubernetes/fake"
utiltesting "k8s.io/client-go/util/testing" utiltesting "k8s.io/client-go/util/testing"
@ -39,29 +40,18 @@ var (
testSioPD = "default" testSioPD = "default"
testSioVol = "vol-0001" testSioVol = "vol-0001"
testns = "default" testns = "default"
testSecret = "sio-secret"
testSioVolName = fmt.Sprintf("%s%s%s", testns, "-", testSioVol) testSioVolName = fmt.Sprintf("%s%s%s", testns, "-", testSioVol)
podUID = types.UID("sio-pod") podUID = types.UID("sio-pod")
) )
func newPluginMgr(t *testing.T) (*volume.VolumePluginMgr, string) { func newPluginMgr(t *testing.T, apiObject runtime.Object) (*volume.VolumePluginMgr, string) {
tmpDir, err := utiltesting.MkTmpdir("scaleio-test") tmpDir, err := utiltesting.MkTmpdir("scaleio-test")
if err != nil { if err != nil {
t.Fatalf("can't make a temp dir: %v", err) t.Fatalf("can't make a temp dir: %v", err)
} }
config := &api.Secret{
ObjectMeta: meta.ObjectMeta{
Name: "sio-secret",
Namespace: testns,
UID: "1234567890",
},
Type: api.SecretType("kubernetes.io/scaleio"),
Data: map[string][]byte{
"username": []byte("username"),
"password": []byte("password"),
},
}
fakeClient := fakeclient.NewSimpleClientset(config) fakeClient := fakeclient.NewSimpleClientset(apiObject)
host := volumetest.NewFakeVolumeHostWithNodeLabels( host := volumetest.NewFakeVolumeHostWithNodeLabels(
tmpDir, tmpDir,
fakeClient, fakeClient,
@ -74,8 +64,23 @@ func newPluginMgr(t *testing.T) (*volume.VolumePluginMgr, string) {
return plugMgr, tmpDir return plugMgr, tmpDir
} }
func makeScaleIOSecret(name, namespace string) *api.Secret {
return &api.Secret{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: namespace,
UID: "1234567890",
},
Type: api.SecretType("kubernetes.io/scaleio"),
Data: map[string][]byte{
"username": []byte("username"),
"password": []byte("password"),
},
}
}
func TestVolumeCanSupport(t *testing.T) { func TestVolumeCanSupport(t *testing.T) {
plugMgr, tmpDir := newPluginMgr(t) plugMgr, tmpDir := newPluginMgr(t, makeScaleIOSecret(testSecret, testns))
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plug, err := plugMgr.FindPluginByName(sioPluginName) plug, err := plugMgr.FindPluginByName(sioPluginName)
if err != nil { if err != nil {
@ -100,7 +105,7 @@ func TestVolumeCanSupport(t *testing.T) {
PersistentVolume: &api.PersistentVolume{ PersistentVolume: &api.PersistentVolume{
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{ PersistentVolumeSource: api.PersistentVolumeSource{
ScaleIO: &api.ScaleIOVolumeSource{}, ScaleIO: &api.ScaleIOPersistentVolumeSource{},
}, },
}, },
}, },
@ -111,7 +116,7 @@ func TestVolumeCanSupport(t *testing.T) {
} }
func TestVolumeGetAccessModes(t *testing.T) { func TestVolumeGetAccessModes(t *testing.T) {
plugMgr, tmpDir := newPluginMgr(t) plugMgr, tmpDir := newPluginMgr(t, makeScaleIOSecret(testSecret, testns))
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plug, err := plugMgr.FindPersistentPluginByName(sioPluginName) plug, err := plugMgr.FindPersistentPluginByName(sioPluginName)
if err != nil { if err != nil {
@ -131,7 +136,7 @@ func containsMode(modes []api.PersistentVolumeAccessMode, mode api.PersistentVol
} }
func TestVolumeMounterUnmounter(t *testing.T) { func TestVolumeMounterUnmounter(t *testing.T) {
plugMgr, tmpDir := newPluginMgr(t) plugMgr, tmpDir := newPluginMgr(t, makeScaleIOSecret(testSecret, testns))
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plug, err := plugMgr.FindPluginByName(sioPluginName) plug, err := plugMgr.FindPluginByName(sioPluginName)
@ -153,7 +158,7 @@ func TestVolumeMounterUnmounter(t *testing.T) {
StoragePool: "default", StoragePool: "default",
VolumeName: testSioVol, VolumeName: testSioVol,
FSType: "ext4", FSType: "ext4",
SecretRef: &api.LocalObjectReference{Name: "sio-secret"}, SecretRef: &api.LocalObjectReference{Name: testSecret},
ReadOnly: false, ReadOnly: false,
}, },
}, },
@ -245,7 +250,7 @@ func TestVolumeMounterUnmounter(t *testing.T) {
} }
func TestVolumeProvisioner(t *testing.T) { func TestVolumeProvisioner(t *testing.T) {
plugMgr, tmpDir := newPluginMgr(t) plugMgr, tmpDir := newPluginMgr(t, makeScaleIOSecret(testSecret, testns))
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plug, err := plugMgr.FindPluginByName(sioPluginName) plug, err := plugMgr.FindPluginByName(sioPluginName)
@ -274,7 +279,7 @@ func TestVolumeProvisioner(t *testing.T) {
confKey.system: "sio", confKey.system: "sio",
confKey.protectionDomain: testSioPD, confKey.protectionDomain: testSioPD,
confKey.storagePool: "default", confKey.storagePool: "default",
confKey.secretRef: "sio-secret", confKey.secretName: testSecret,
} }
provisioner, err := sioPlug.NewProvisioner(options) provisioner, err := sioPlug.NewProvisioner(options)
@ -296,6 +301,17 @@ func TestVolumeProvisioner(t *testing.T) {
t.Fatalf("call to Provision() failed: %v", err) t.Fatalf("call to Provision() failed: %v", err)
} }
if spec.Namespace != testns {
t.Fatalf("unexpected namespace %v", spec.Namespace)
}
if spec.Spec.ScaleIO.SecretRef == nil {
t.Fatalf("unexpected nil value for spec.SecretRef")
}
if spec.Spec.ScaleIO.SecretRef.Name != testSecret ||
spec.Spec.ScaleIO.SecretRef.Namespace != testns {
t.Fatalf("spec.SecretRef is not being set properly")
}
spec.Spec.ClaimRef = &api.ObjectReference{Namespace: testns} spec.Spec.ClaimRef = &api.ObjectReference{Namespace: testns}
// validate provision // validate provision
@ -379,7 +395,7 @@ func TestVolumeProvisioner(t *testing.T) {
} }
func TestVolumeProvisionerWithIncompleteConfig(t *testing.T) { func TestVolumeProvisionerWithIncompleteConfig(t *testing.T) {
plugMgr, tmpDir := newPluginMgr(t) plugMgr, tmpDir := newPluginMgr(t, makeScaleIOSecret(testSecret, testns))
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plug, err := plugMgr.FindPluginByName(sioPluginName) plug, err := plugMgr.FindPluginByName(sioPluginName)
@ -411,7 +427,7 @@ func TestVolumeProvisionerWithIncompleteConfig(t *testing.T) {
} }
func TestVolumeProvisionerWithZeroCapacity(t *testing.T) { func TestVolumeProvisionerWithZeroCapacity(t *testing.T) {
plugMgr, tmpDir := newPluginMgr(t) plugMgr, tmpDir := newPluginMgr(t, makeScaleIOSecret(testSecret, testns))
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
plug, err := plugMgr.FindPluginByName(sioPluginName) plug, err := plugMgr.FindPluginByName(sioPluginName)
@ -440,7 +456,7 @@ func TestVolumeProvisionerWithZeroCapacity(t *testing.T) {
confKey.system: "sio", confKey.system: "sio",
confKey.protectionDomain: testSioPD, confKey.protectionDomain: testSioPD,
confKey.storagePool: "default", confKey.storagePool: "default",
confKey.secretRef: "sio-secret", confKey.secretName: "sio-secret",
} }
provisioner, _ := sioPlug.NewProvisioner(options) provisioner, _ := sioPlug.NewProvisioner(options)
@ -457,3 +473,63 @@ func TestVolumeProvisionerWithZeroCapacity(t *testing.T) {
} }
} }
func TestVolumeProvisionerWithSecretNamespace(t *testing.T) {
plugMgr, tmpDir := newPluginMgr(t, makeScaleIOSecret("sio-sec", "sio-ns"))
defer os.RemoveAll(tmpDir)
plug, err := plugMgr.FindPluginByName(sioPluginName)
if err != nil {
t.Fatalf("Can't find the plugin %v", sioPluginName)
}
sioPlug, ok := plug.(*sioPlugin)
if !ok {
t.Fatal("Cannot assert plugin to be type sioPlugin")
}
options := volume.VolumeOptions{
ClusterName: "testcluster",
PVName: "pvc-sio-dynamic-vol",
PVC: volumetest.CreateTestPVC("100Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}),
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
}
options.PVC.Spec.AccessModes = []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
}
options.PVC.Namespace = "pvc-ns"
options.Parameters = map[string]string{
confKey.gateway: "http://test.scaleio:11111",
confKey.system: "sio",
confKey.protectionDomain: testSioPD,
confKey.storagePool: "default",
confKey.secretName: "sio-sec",
confKey.secretNamespace: "sio-ns",
}
provisioner, _ := sioPlug.NewProvisioner(options)
sio := newFakeSio()
sioVol := provisioner.(*sioVolume)
if err := sioVol.setSioMgrFromConfig(); err != nil {
t.Fatalf("failed to create scaleio mgr from config: %v", err)
}
sioVol.sioMgr.client = sio
spec, err := sioVol.Provision()
if err != nil {
t.Fatalf("call to Provision() failed: %v", err)
}
if spec.GetObjectMeta().GetNamespace() != "pvc-ns" {
t.Fatalf("unexpected spec.namespace %s", spec.GetObjectMeta().GetNamespace())
}
if spec.Spec.ScaleIO.SecretRef.Name != "sio-sec" {
t.Fatalf("unexpected spec.ScaleIOPersistentVolume.SecretRef.Name %v", spec.Spec.ScaleIO.SecretRef.Name)
}
if spec.Spec.ScaleIO.SecretRef.Namespace != "sio-ns" {
t.Fatalf("unexpected spec.ScaleIOPersistentVolume.SecretRef.Namespace %v", spec.Spec.ScaleIO.SecretRef.Namespace)
}
}

View File

@ -440,7 +440,7 @@ type PersistentVolumeSource struct {
PortworxVolume *PortworxVolumeSource `json:"portworxVolume,omitempty" protobuf:"bytes,18,opt,name=portworxVolume"` PortworxVolume *PortworxVolumeSource `json:"portworxVolume,omitempty" protobuf:"bytes,18,opt,name=portworxVolume"`
// ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. // ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.
// +optional // +optional
ScaleIO *ScaleIOVolumeSource `json:"scaleIO,omitempty" protobuf:"bytes,19,opt,name=scaleIO"` ScaleIO *ScaleIOPersistentVolumeSource `json:"scaleIO,omitempty" protobuf:"bytes,19,opt,name=scaleIO"`
// Local represents directly-attached storage with node affinity // Local represents directly-attached storage with node affinity
// +optional // +optional
Local *LocalVolumeSource `json:"local,omitempty" protobuf:"bytes,20,opt,name=local"` Local *LocalVolumeSource `json:"local,omitempty" protobuf:"bytes,20,opt,name=local"`
@ -1396,13 +1396,48 @@ type ScaleIOVolumeSource struct {
// Flag to enable/disable SSL communication with Gateway, default false // Flag to enable/disable SSL communication with Gateway, default false
// +optional // +optional
SSLEnabled bool `json:"sslEnabled,omitempty" protobuf:"varint,4,opt,name=sslEnabled"` SSLEnabled bool `json:"sslEnabled,omitempty" protobuf:"varint,4,opt,name=sslEnabled"`
// The name of the Protection Domain for the configured storage (defaults to "default"). // The name of the ScaleIO Protection Domain for the configured storage.
// +optional // +optional
ProtectionDomain string `json:"protectionDomain,omitempty" protobuf:"bytes,5,opt,name=protectionDomain"` ProtectionDomain string `json:"protectionDomain,omitempty" protobuf:"bytes,5,opt,name=protectionDomain"`
// The Storage Pool associated with the protection domain (defaults to "default"). // The ScaleIO Storage Pool associated with the protection domain.
// +optional // +optional
StoragePool string `json:"storagePool,omitempty" protobuf:"bytes,6,opt,name=storagePool"` StoragePool string `json:"storagePool,omitempty" protobuf:"bytes,6,opt,name=storagePool"`
// Indicates whether the storage for a volume should be thick or thin (defaults to "thin"). // Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.
// +optional
StorageMode string `json:"storageMode,omitempty" protobuf:"bytes,7,opt,name=storageMode"`
// The name of a volume already created in the ScaleIO system
// that is associated with this volume source.
VolumeName string `json:"volumeName,omitempty" protobuf:"bytes,8,opt,name=volumeName"`
// Filesystem type to mount.
// Must be a filesystem type supported by the host operating system.
// Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
// +optional
FSType string `json:"fsType,omitempty" protobuf:"bytes,9,opt,name=fsType"`
// Defaults to false (read/write). ReadOnly here will force
// the ReadOnly setting in VolumeMounts.
// +optional
ReadOnly bool `json:"readOnly,omitempty" protobuf:"varint,10,opt,name=readOnly"`
}
// ScaleIOPersistentVolumeSource represents a persistent ScaleIO volume
type ScaleIOPersistentVolumeSource struct {
// The host address of the ScaleIO API Gateway.
Gateway string `json:"gateway" protobuf:"bytes,1,opt,name=gateway"`
// The name of the storage system as configured in ScaleIO.
System string `json:"system" protobuf:"bytes,2,opt,name=system"`
// SecretRef references to the secret for ScaleIO user and other
// sensitive information. If this is not provided, Login operation will fail.
SecretRef *SecretReference `json:"secretRef" protobuf:"bytes,3,opt,name=secretRef"`
// Flag to enable/disable SSL communication with Gateway, default false
// +optional
SSLEnabled bool `json:"sslEnabled,omitempty" protobuf:"varint,4,opt,name=sslEnabled"`
// The name of the ScaleIO Protection Domain for the configured storage.
// +optional
ProtectionDomain string `json:"protectionDomain,omitempty" protobuf:"bytes,5,opt,name=protectionDomain"`
// The ScaleIO Storage Pool associated with the protection domain.
// +optional
StoragePool string `json:"storagePool,omitempty" protobuf:"bytes,6,opt,name=storagePool"`
// Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.
// +optional // +optional
StorageMode string `json:"storageMode,omitempty" protobuf:"bytes,7,opt,name=storageMode"` StorageMode string `json:"storageMode,omitempty" protobuf:"bytes,7,opt,name=storageMode"`
// The name of a volume already created in the ScaleIO system // The name of a volume already created in the ScaleIO system