mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
use SecretObject to reference iSCSI CHAP secret
Signed-off-by: Huamin Chen <hchen@redhat.com>
This commit is contained in:
parent
02f803cc02
commit
bb34a0b7ef
@ -88,8 +88,16 @@ func VisitPVSecretNames(pv *api.PersistentVolume, visitor Visitor) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 {
|
||||||
return false
|
// previously persisted PV objects use claimRef namespace
|
||||||
|
ns := getClaimRefNamespace(pv)
|
||||||
|
if len(source.ISCSI.SecretRef.Namespace) > 0 {
|
||||||
|
// use the secret namespace if namespace is set
|
||||||
|
ns = source.ISCSI.SecretRef.Namespace
|
||||||
|
}
|
||||||
|
if !visitor(ns, source.ISCSI.SecretRef.Name) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case source.StorageOS != nil:
|
case source.StorageOS != nil:
|
||||||
if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Namespace, source.StorageOS.SecretRef.Name) {
|
if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Namespace, source.StorageOS.SecretRef.Name) {
|
||||||
|
@ -93,8 +93,15 @@ 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{
|
||||||
ISCSI: &api.ISCSIVolumeSource{
|
ISCSI: &api.ISCSIPersistentVolumeSource{
|
||||||
SecretRef: &api.LocalObjectReference{
|
SecretRef: &api.SecretReference{
|
||||||
|
Name: "Spec.PersistentVolumeSource.ISCSI.SecretRef",
|
||||||
|
Namespace: "iscsi"}}}}},
|
||||||
|
{Spec: api.PersistentVolumeSpec{
|
||||||
|
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||||
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
|
ISCSI: &api.ISCSIPersistentVolumeSource{
|
||||||
|
SecretRef: &api.SecretReference{
|
||||||
Name: "Spec.PersistentVolumeSource.ISCSI.SecretRef"}}}}},
|
Name: "Spec.PersistentVolumeSource.ISCSI.SecretRef"}}}}},
|
||||||
{Spec: api.PersistentVolumeSpec{
|
{Spec: api.PersistentVolumeSpec{
|
||||||
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||||
@ -161,6 +168,7 @@ func TestPVSecrets(t *testing.T) {
|
|||||||
"claimrefns/Spec.PersistentVolumeSource.ScaleIO.SecretRef",
|
"claimrefns/Spec.PersistentVolumeSource.ScaleIO.SecretRef",
|
||||||
"scaleions/Spec.PersistentVolumeSource.ScaleIO.SecretRef",
|
"scaleions/Spec.PersistentVolumeSource.ScaleIO.SecretRef",
|
||||||
"claimrefns/Spec.PersistentVolumeSource.ISCSI.SecretRef",
|
"claimrefns/Spec.PersistentVolumeSource.ISCSI.SecretRef",
|
||||||
|
"iscsi/Spec.PersistentVolumeSource.ISCSI.SecretRef",
|
||||||
"storageosns/Spec.PersistentVolumeSource.StorageOS.SecretRef",
|
"storageosns/Spec.PersistentVolumeSource.StorageOS.SecretRef",
|
||||||
)
|
)
|
||||||
if missingNames := expectedNamespacedNames.Difference(extractedNamesWithNamespace); len(missingNames) > 0 {
|
if missingNames := expectedNamespacedNames.Difference(extractedNamesWithNamespace); len(missingNames) > 0 {
|
||||||
|
@ -245,6 +245,12 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
i.ISCSIInterface = "default"
|
i.ISCSIInterface = "default"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
func(i *core.ISCSIPersistentVolumeSource, c fuzz.Continue) {
|
||||||
|
i.ISCSIInterface = c.RandString()
|
||||||
|
if i.ISCSIInterface == "" {
|
||||||
|
i.ISCSIInterface = "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
func(d *core.DNSPolicy, c fuzz.Continue) {
|
func(d *core.DNSPolicy, c fuzz.Continue) {
|
||||||
policies := []core.DNSPolicy{core.DNSClusterFirst, core.DNSDefault}
|
policies := []core.DNSPolicy{core.DNSClusterFirst, core.DNSDefault}
|
||||||
*d = policies[c.Rand.Intn(len(policies))]
|
*d = policies[c.Rand.Intn(len(policies))]
|
||||||
|
@ -347,10 +347,10 @@ type PersistentVolumeSource struct {
|
|||||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||||
// +optional
|
// +optional
|
||||||
Quobyte *QuobyteVolumeSource
|
Quobyte *QuobyteVolumeSource
|
||||||
// ISCSIVolumeSource represents an ISCSI resource that is attached to a
|
// ISCSIPersistentVolumeSource represents an ISCSI resource that is attached to a
|
||||||
// kubelet's host machine and then exposed to the pod.
|
// kubelet's host machine and then exposed to the pod.
|
||||||
// +optional
|
// +optional
|
||||||
ISCSI *ISCSIVolumeSource
|
ISCSI *ISCSIPersistentVolumeSource
|
||||||
// FlexVolume represents a generic volume resource that is
|
// FlexVolume represents a generic volume resource that is
|
||||||
// provisioned/attached using an exec based plugin. This is an alpha feature and may change in future.
|
// provisioned/attached using an exec based plugin. This is an alpha feature and may change in future.
|
||||||
// +optional
|
// +optional
|
||||||
@ -793,6 +793,54 @@ type ISCSIVolumeSource struct {
|
|||||||
InitiatorName *string
|
InitiatorName *string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ISCSIPersistentVolumeSource represents an ISCSI disk.
|
||||||
|
// ISCSI volumes can only be mounted as read/write once.
|
||||||
|
// ISCSI volumes support ownership management and SELinux relabeling.
|
||||||
|
type ISCSIPersistentVolumeSource struct {
|
||||||
|
// Required: iSCSI target portal
|
||||||
|
// the portal is either an IP or ip_addr:port if port is other than default (typically TCP ports 860 and 3260)
|
||||||
|
// +optional
|
||||||
|
TargetPortal string
|
||||||
|
// Required: target iSCSI Qualified Name
|
||||||
|
// +optional
|
||||||
|
IQN string
|
||||||
|
// Required: iSCSI target lun number
|
||||||
|
// +optional
|
||||||
|
Lun int32
|
||||||
|
// Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport.
|
||||||
|
// +optional
|
||||||
|
ISCSIInterface 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.
|
||||||
|
// TODO: how do we prevent errors in the filesystem from compromising the machine
|
||||||
|
// +optional
|
||||||
|
FSType string
|
||||||
|
// Optional: Defaults to false (read/write). ReadOnly here will force
|
||||||
|
// the ReadOnly setting in VolumeMounts.
|
||||||
|
// +optional
|
||||||
|
ReadOnly bool
|
||||||
|
// Optional: list of iSCSI target portal ips for high availability.
|
||||||
|
// the portal is either an IP or ip_addr:port if port is other than default (typically TCP ports 860 and 3260)
|
||||||
|
// +optional
|
||||||
|
Portals []string
|
||||||
|
// Optional: whether support iSCSI Discovery CHAP authentication
|
||||||
|
// +optional
|
||||||
|
DiscoveryCHAPAuth bool
|
||||||
|
// Optional: whether support iSCSI Session CHAP authentication
|
||||||
|
// +optional
|
||||||
|
SessionCHAPAuth bool
|
||||||
|
// Optional: CHAP secret for iSCSI target and initiator authentication.
|
||||||
|
// The secret is used if either DiscoveryCHAPAuth or SessionCHAPAuth is true
|
||||||
|
// +optional
|
||||||
|
SecretRef *SecretReference
|
||||||
|
// Optional: Custom initiator name per volume.
|
||||||
|
// If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface
|
||||||
|
// <target portal>:<volume name> will be created for the connection.
|
||||||
|
// +optional
|
||||||
|
InitiatorName *string
|
||||||
|
}
|
||||||
|
|
||||||
// Represents a Fibre Channel volume.
|
// Represents a Fibre Channel volume.
|
||||||
// Fibre Channel volumes can only be mounted as read/write once.
|
// Fibre Channel volumes can only be mounted as read/write once.
|
||||||
// Fibre Channel volumes support ownership management and SELinux relabeling.
|
// Fibre Channel volumes support ownership management and SELinux relabeling.
|
||||||
|
@ -249,6 +249,11 @@ func SetDefaults_ISCSIVolumeSource(obj *v1.ISCSIVolumeSource) {
|
|||||||
obj.ISCSIInterface = "default"
|
obj.ISCSIInterface = "default"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func SetDefaults_ISCSIPersistentVolumeSource(obj *v1.ISCSIPersistentVolumeSource) {
|
||||||
|
if obj.ISCSIInterface == "" {
|
||||||
|
obj.ISCSIInterface = "default"
|
||||||
|
}
|
||||||
|
}
|
||||||
func SetDefaults_AzureDiskVolumeSource(obj *v1.AzureDiskVolumeSource) {
|
func SetDefaults_AzureDiskVolumeSource(obj *v1.AzureDiskVolumeSource) {
|
||||||
if obj.CachingMode == nil {
|
if obj.CachingMode == nil {
|
||||||
obj.CachingMode = new(v1.AzureDataDiskCachingMode)
|
obj.CachingMode = new(v1.AzureDataDiskCachingMode)
|
||||||
|
@ -712,6 +712,46 @@ func validateGitRepoVolumeSource(gitRepo *core.GitRepoVolumeSource, fldPath *fie
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateISCSIVolumeSource(iscsi *core.ISCSIVolumeSource, fldPath *field.Path) field.ErrorList {
|
func validateISCSIVolumeSource(iscsi *core.ISCSIVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
if len(iscsi.TargetPortal) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"), ""))
|
||||||
|
}
|
||||||
|
if len(iscsi.IQN) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(fldPath.Child("iqn"), ""))
|
||||||
|
} else {
|
||||||
|
if !strings.HasPrefix(iscsi.IQN, "iqn") && !strings.HasPrefix(iscsi.IQN, "eui") && !strings.HasPrefix(iscsi.IQN, "naa") {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format starting with iqn, eui, or naa"))
|
||||||
|
} else if strings.HasPrefix(iscsi.IQN, "iqn") && !iscsiInitiatorIqnRegex.MatchString(iscsi.IQN) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
|
||||||
|
} else if strings.HasPrefix(iscsi.IQN, "eui") && !iscsiInitiatorEuiRegex.MatchString(iscsi.IQN) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
|
||||||
|
} else if strings.HasPrefix(iscsi.IQN, "naa") && !iscsiInitiatorNaaRegex.MatchString(iscsi.IQN) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iscsi.Lun < 0 || iscsi.Lun > 255 {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), iscsi.Lun, validation.InclusiveRangeError(0, 255)))
|
||||||
|
}
|
||||||
|
if (iscsi.DiscoveryCHAPAuth || iscsi.SessionCHAPAuth) && iscsi.SecretRef == nil {
|
||||||
|
allErrs = append(allErrs, field.Required(fldPath.Child("secretRef"), ""))
|
||||||
|
}
|
||||||
|
if iscsi.InitiatorName != nil {
|
||||||
|
initiator := *iscsi.InitiatorName
|
||||||
|
if !strings.HasPrefix(initiator, "iqn") && !strings.HasPrefix(initiator, "eui") && !strings.HasPrefix(initiator, "naa") {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format starting with iqn, eui, or naa"))
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(initiator, "iqn") && !iscsiInitiatorIqnRegex.MatchString(initiator) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
|
||||||
|
} else if strings.HasPrefix(initiator, "eui") && !iscsiInitiatorEuiRegex.MatchString(initiator) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
|
||||||
|
} else if strings.HasPrefix(initiator, "naa") && !iscsiInitiatorNaaRegex.MatchString(initiator) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateISCSIPersistentVolumeSource(iscsi *core.ISCSIPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
if len(iscsi.TargetPortal) == 0 {
|
if len(iscsi.TargetPortal) == 0 {
|
||||||
allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"), ""))
|
allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"), ""))
|
||||||
@ -735,6 +775,11 @@ func validateISCSIVolumeSource(iscsi *core.ISCSIVolumeSource, fldPath *field.Pat
|
|||||||
if (iscsi.DiscoveryCHAPAuth || iscsi.SessionCHAPAuth) && iscsi.SecretRef == nil {
|
if (iscsi.DiscoveryCHAPAuth || iscsi.SessionCHAPAuth) && iscsi.SecretRef == nil {
|
||||||
allErrs = append(allErrs, field.Required(fldPath.Child("secretRef"), ""))
|
allErrs = append(allErrs, field.Required(fldPath.Child("secretRef"), ""))
|
||||||
}
|
}
|
||||||
|
if iscsi.SecretRef != nil {
|
||||||
|
if len(iscsi.SecretRef.Name) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
if iscsi.InitiatorName != nil {
|
if iscsi.InitiatorName != nil {
|
||||||
initiator := *iscsi.InitiatorName
|
initiator := *iscsi.InitiatorName
|
||||||
if !strings.HasPrefix(initiator, "iqn") && !strings.HasPrefix(initiator, "eui") && !strings.HasPrefix(initiator, "naa") {
|
if !strings.HasPrefix(initiator, "iqn") && !strings.HasPrefix(initiator, "eui") && !strings.HasPrefix(initiator, "naa") {
|
||||||
@ -1517,7 +1562,7 @@ func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
|
|||||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("iscsi"), "may not specify more than 1 volume type"))
|
allErrs = append(allErrs, field.Forbidden(specPath.Child("iscsi"), "may not specify more than 1 volume type"))
|
||||||
} else {
|
} else {
|
||||||
numVolumes++
|
numVolumes++
|
||||||
allErrs = append(allErrs, validateISCSIVolumeSource(pv.Spec.ISCSI, specPath.Child("iscsi"))...)
|
allErrs = append(allErrs, validateISCSIPersistentVolumeSource(pv.Spec.ISCSI, specPath.Child("iscsi"))...)
|
||||||
}
|
}
|
||||||
if pv.Spec.ISCSI.InitiatorName != nil && len(pv.ObjectMeta.Name+":"+pv.Spec.ISCSI.TargetPortal) > 64 {
|
if pv.Spec.ISCSI.InitiatorName != nil && len(pv.ObjectMeta.Name+":"+pv.Spec.ISCSI.TargetPortal) > 64 {
|
||||||
tooLongErr := "Total length of <volume name>:<iscsi.targetPortal> must be under 64 characters if iscsi.initiatorName is specified."
|
tooLongErr := "Total length of <volume name>:<iscsi.targetPortal> must be under 64 characters if iscsi.initiatorName is specified."
|
||||||
|
@ -856,6 +856,26 @@ func printISCSIVolumeSource(iscsi *api.ISCSIVolumeSource, w PrefixWriter) {
|
|||||||
iscsi.TargetPortal, iscsi.IQN, iscsi.Lun, iscsi.ISCSIInterface, iscsi.FSType, iscsi.ReadOnly, iscsi.Portals, iscsi.DiscoveryCHAPAuth, iscsi.SessionCHAPAuth, iscsi.SecretRef, initiator)
|
iscsi.TargetPortal, iscsi.IQN, iscsi.Lun, iscsi.ISCSIInterface, iscsi.FSType, iscsi.ReadOnly, iscsi.Portals, iscsi.DiscoveryCHAPAuth, iscsi.SessionCHAPAuth, iscsi.SecretRef, initiator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printISCSIPersistentVolumeSource(iscsi *api.ISCSIPersistentVolumeSource, w PrefixWriter) {
|
||||||
|
initiatorName := "<none>"
|
||||||
|
if iscsi.InitiatorName != nil {
|
||||||
|
initiatorName = *iscsi.InitiatorName
|
||||||
|
}
|
||||||
|
w.Write(LEVEL_2, "Type:\tISCSI (an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod)\n"+
|
||||||
|
" TargetPortal:\t%v\n"+
|
||||||
|
" IQN:\t%v\n"+
|
||||||
|
" Lun:\t%v\n"+
|
||||||
|
" ISCSIInterface\t%v\n"+
|
||||||
|
" FSType:\t%v\n"+
|
||||||
|
" ReadOnly:\t%v\n"+
|
||||||
|
" Portals:\t%v\n"+
|
||||||
|
" DiscoveryCHAPAuth:\t%v\n"+
|
||||||
|
" SessionCHAPAuth:\t%v\n"+
|
||||||
|
" SecretRef:\t%v\n"+
|
||||||
|
" InitiatorName:\t%v\n",
|
||||||
|
iscsi.TargetPortal, iscsi.IQN, iscsi.Lun, iscsi.ISCSIInterface, iscsi.FSType, iscsi.ReadOnly, iscsi.Portals, iscsi.DiscoveryCHAPAuth, iscsi.SessionCHAPAuth, iscsi.SecretRef, initiatorName)
|
||||||
|
}
|
||||||
|
|
||||||
func printGlusterfsVolumeSource(glusterfs *api.GlusterfsVolumeSource, w PrefixWriter) {
|
func printGlusterfsVolumeSource(glusterfs *api.GlusterfsVolumeSource, w PrefixWriter) {
|
||||||
w.Write(LEVEL_2, "Type:\tGlusterfs (a Glusterfs mount on the host that shares a pod's lifetime)\n"+
|
w.Write(LEVEL_2, "Type:\tGlusterfs (a Glusterfs mount on the host that shares a pod's lifetime)\n"+
|
||||||
" EndpointsName:\t%v\n"+
|
" EndpointsName:\t%v\n"+
|
||||||
@ -1131,7 +1151,7 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (
|
|||||||
case pv.Spec.NFS != nil:
|
case pv.Spec.NFS != nil:
|
||||||
printNFSVolumeSource(pv.Spec.NFS, w)
|
printNFSVolumeSource(pv.Spec.NFS, w)
|
||||||
case pv.Spec.ISCSI != nil:
|
case pv.Spec.ISCSI != nil:
|
||||||
printISCSIVolumeSource(pv.Spec.ISCSI, w)
|
printISCSIPersistentVolumeSource(pv.Spec.ISCSI, w)
|
||||||
case pv.Spec.Glusterfs != nil:
|
case pv.Spec.Glusterfs != nil:
|
||||||
printGlusterfsVolumeSource(pv.Spec.Glusterfs, w)
|
printGlusterfsVolumeSource(pv.Spec.Glusterfs, w)
|
||||||
case pv.Spec.RBD != nil:
|
case pv.Spec.RBD != nil:
|
||||||
|
@ -853,7 +853,7 @@ func TestPersistentVolumeDescriber(t *testing.T) {
|
|||||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||||
Spec: api.PersistentVolumeSpec{
|
Spec: api.PersistentVolumeSpec{
|
||||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||||
ISCSI: &api.ISCSIVolumeSource{},
|
ISCSI: &api.ISCSIPersistentVolumeSource{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -23,6 +23,7 @@ go_library(
|
|||||||
"//pkg/volume/util:go_default_library",
|
"//pkg/volume/util:go_default_library",
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
@ -100,7 +101,7 @@ func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
volumeSource, readOnly, err := getVolumeSource(spec)
|
readOnly, fsType, err := getISCSIVolumeInfo(spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -112,7 +113,7 @@ func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string,
|
|||||||
if notMnt {
|
if notMnt {
|
||||||
diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Exec: attacher.host.GetExec(iscsiPluginName)}
|
diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Exec: attacher.host.GetExec(iscsiPluginName)}
|
||||||
mountOptions := volume.MountOptionFromSpec(spec, options...)
|
mountOptions := volume.MountOptionFromSpec(spec, options...)
|
||||||
err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions)
|
err = diskMounter.FormatAndMount(devicePath, deviceMountPath, fsType, mountOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Remove(deviceMountPath)
|
os.Remove(deviceMountPath)
|
||||||
return err
|
return err
|
||||||
@ -159,29 +160,75 @@ func (detacher *iscsiDetacher) UnmountDevice(deviceMountPath string) error {
|
|||||||
func (attacher *iscsiAttacher) volumeSpecToMounter(spec *volume.Spec, host volume.VolumeHost, pod *v1.Pod) (*iscsiDiskMounter, error) {
|
func (attacher *iscsiAttacher) volumeSpecToMounter(spec *volume.Spec, host volume.VolumeHost, pod *v1.Pod) (*iscsiDiskMounter, error) {
|
||||||
var secret map[string]string
|
var secret map[string]string
|
||||||
var bkportal []string
|
var bkportal []string
|
||||||
iscsi, readOnly, err := getVolumeSource(spec)
|
readOnly, fsType, err := getISCSIVolumeInfo(spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Obtain secret for AttachDisk
|
if pod != nil {
|
||||||
if iscsi.SecretRef != nil && pod != nil {
|
chapDiscovery, err := getISCSIDiscoveryCHAPInfo(spec)
|
||||||
if secret, err = volumeutil.GetSecretForPod(pod, iscsi.SecretRef.Name, host.GetKubeClient()); err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Couldn't get secret from %v/%v", pod.Namespace, iscsi.SecretRef)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
chapSession, err := getISCSISessionCHAPInfo(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if chapDiscovery || chapSession {
|
||||||
|
secretName, secretNamespace, err := getISCSISecretNameAndNamespace(spec, pod.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(secretNamespace) == 0 || len(secretName) == 0 {
|
||||||
|
return nil, fmt.Errorf("CHAP enabled but secret name or namespace is empty")
|
||||||
|
}
|
||||||
|
// if secret is provided, retrieve it
|
||||||
|
kubeClient := host.GetKubeClient()
|
||||||
|
if kubeClient == nil {
|
||||||
|
return nil, fmt.Errorf("Cannot get kube client")
|
||||||
|
}
|
||||||
|
secretObj, err := kubeClient.Core().Secrets(secretNamespace).Get(secretName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Couldn't get secret %v/%v error: %v", secretNamespace, secretName, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
secret = make(map[string]string)
|
||||||
|
for name, data := range secretObj.Data {
|
||||||
|
glog.V(6).Infof("retrieving CHAP secret name: %s", name)
|
||||||
|
secret[name] = string(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
lun := strconv.Itoa(int(iscsi.Lun))
|
tp, portals, iqn, lunStr, err := getISCSITargetInfo(spec)
|
||||||
portal := portalMounter(iscsi.TargetPortal)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
lun := strconv.Itoa(int(lunStr))
|
||||||
|
portal := portalMounter(tp)
|
||||||
bkportal = append(bkportal, portal)
|
bkportal = append(bkportal, portal)
|
||||||
for _, tp := range iscsi.Portals {
|
for _, p := range portals {
|
||||||
bkportal = append(bkportal, portalMounter(string(tp)))
|
bkportal = append(bkportal, portalMounter(string(p)))
|
||||||
}
|
}
|
||||||
iface := iscsi.ISCSIInterface
|
|
||||||
exec := attacher.host.GetExec(iscsiPluginName)
|
iface, initiatorNamePtr, err := getISCSIInitiatorInfo(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var initiatorName string
|
var initiatorName string
|
||||||
if iscsi.InitiatorName != nil {
|
if initiatorNamePtr != nil {
|
||||||
initiatorName = *iscsi.InitiatorName
|
initiatorName = *initiatorNamePtr
|
||||||
}
|
}
|
||||||
|
chapDiscovery, err := getISCSIDiscoveryCHAPInfo(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
chapSession, err := getISCSISessionCHAPInfo(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
exec := attacher.host.GetExec(iscsiPluginName)
|
||||||
|
|
||||||
return &iscsiDiskMounter{
|
return &iscsiDiskMounter{
|
||||||
iscsiDisk: &iscsiDisk{
|
iscsiDisk: &iscsiDisk{
|
||||||
@ -190,15 +237,15 @@ func (attacher *iscsiAttacher) volumeSpecToMounter(spec *volume.Spec, host volum
|
|||||||
},
|
},
|
||||||
VolName: spec.Name(),
|
VolName: spec.Name(),
|
||||||
Portals: bkportal,
|
Portals: bkportal,
|
||||||
Iqn: iscsi.IQN,
|
Iqn: iqn,
|
||||||
lun: lun,
|
lun: lun,
|
||||||
Iface: iface,
|
Iface: iface,
|
||||||
chap_discovery: iscsi.DiscoveryCHAPAuth,
|
chap_discovery: chapDiscovery,
|
||||||
chap_session: iscsi.SessionCHAPAuth,
|
chap_session: chapSession,
|
||||||
secret: secret,
|
secret: secret,
|
||||||
InitiatorName: initiatorName,
|
InitiatorName: initiatorName,
|
||||||
manager: &ISCSIUtil{}},
|
manager: &ISCSIUtil{}},
|
||||||
fsType: iscsi.FSType,
|
fsType: fsType,
|
||||||
readOnly: readOnly,
|
readOnly: readOnly,
|
||||||
mounter: &mount.SafeFormatAndMount{Interface: host.GetMounter(iscsiPluginName), Exec: exec},
|
mounter: &mount.SafeFormatAndMount{Interface: host.GetMounter(iscsiPluginName), Exec: exec},
|
||||||
exec: exec,
|
exec: exec,
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
utilstrings "k8s.io/kubernetes/pkg/util/strings"
|
utilstrings "k8s.io/kubernetes/pkg/util/strings"
|
||||||
@ -56,16 +57,12 @@ func (plugin *iscsiPlugin) GetPluginName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (plugin *iscsiPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
|
func (plugin *iscsiPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
|
||||||
volumeSource, _, err := getVolumeSource(spec)
|
tp, _, iqn, lun, err := getISCSITargetInfo(spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf("%v:%v:%v", tp, iqn, lun), nil
|
||||||
"%v:%v:%v",
|
|
||||||
volumeSource.TargetPortal,
|
|
||||||
volumeSource.IQN,
|
|
||||||
volumeSource.Lun), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (plugin *iscsiPlugin) CanSupport(spec *volume.Spec) bool {
|
func (plugin *iscsiPlugin) CanSupport(spec *volume.Spec) bool {
|
||||||
@ -98,41 +95,80 @@ func (plugin *iscsiPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
|
|||||||
func (plugin *iscsiPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
|
func (plugin *iscsiPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
|
||||||
// Inject real implementations here, test through the internal function.
|
// Inject real implementations here, test through the internal function.
|
||||||
var secret map[string]string
|
var secret map[string]string
|
||||||
source, _, err := getVolumeSource(spec)
|
if pod == nil {
|
||||||
|
return nil, fmt.Errorf("nil pod")
|
||||||
|
}
|
||||||
|
chapDiscover, err := getISCSIDiscoveryCHAPInfo(spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
chapSession, err := getISCSISessionCHAPInfo(spec)
|
||||||
if source.SecretRef != nil {
|
if err != nil {
|
||||||
if secret, err = ioutil.GetSecretForPod(pod, source.SecretRef.Name, plugin.host.GetKubeClient()); err != nil {
|
return nil, err
|
||||||
glog.Errorf("Couldn't get secret from %v/%v", pod.Namespace, source.SecretRef)
|
}
|
||||||
|
if chapDiscover || chapSession {
|
||||||
|
secretName, secretNamespace, err := getISCSISecretNameAndNamespace(spec, pod.Namespace)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if len(secretName) > 0 && len(secretNamespace) > 0 {
|
||||||
|
// if secret is provideded, retrieve it
|
||||||
|
kubeClient := plugin.host.GetKubeClient()
|
||||||
|
if kubeClient == nil {
|
||||||
|
return nil, fmt.Errorf("Cannot get kube client")
|
||||||
|
}
|
||||||
|
secretObj, err := kubeClient.Core().Secrets(secretNamespace).Get(secretName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Couldn't get secret %v/%v error: %v", secretNamespace, secretName, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
secret = make(map[string]string)
|
||||||
|
for name, data := range secretObj.Data {
|
||||||
|
glog.V(4).Infof("retrieving CHAP secret name: %s", name)
|
||||||
|
secret[name] = string(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return plugin.newMounterInternal(spec, pod.UID, &ISCSIUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()), secret)
|
return plugin.newMounterInternal(spec, pod.UID, &ISCSIUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()), secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec, secret map[string]string) (volume.Mounter, error) {
|
func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec, secret map[string]string) (volume.Mounter, error) {
|
||||||
// iscsi volumes used directly in a pod have a ReadOnly flag set by the pod author.
|
// iscsi volumes used directly in a pod have a ReadOnly flag set by the pod author.
|
||||||
// iscsi volumes used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
|
// iscsi volumes used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
|
||||||
iscsi, readOnly, err := getVolumeSource(spec)
|
readOnly, fsType, err := getISCSIVolumeInfo(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp, portals, iqn, lunStr, err := getISCSITargetInfo(spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
lun := strconv.Itoa(int(iscsi.Lun))
|
lun := strconv.Itoa(int(lunStr))
|
||||||
portal := portalMounter(iscsi.TargetPortal)
|
portal := portalMounter(tp)
|
||||||
var bkportal []string
|
var bkportal []string
|
||||||
bkportal = append(bkportal, portal)
|
bkportal = append(bkportal, portal)
|
||||||
for _, tp := range iscsi.Portals {
|
for _, p := range portals {
|
||||||
bkportal = append(bkportal, portalMounter(string(tp)))
|
bkportal = append(bkportal, portalMounter(string(p)))
|
||||||
|
}
|
||||||
|
|
||||||
|
iface, initiatorNamePtr, err := getISCSIInitiatorInfo(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
iface := iscsi.ISCSIInterface
|
|
||||||
|
|
||||||
var initiatorName string
|
var initiatorName string
|
||||||
if iscsi.InitiatorName != nil {
|
if initiatorNamePtr != nil {
|
||||||
initiatorName = *iscsi.InitiatorName
|
initiatorName = *initiatorNamePtr
|
||||||
|
}
|
||||||
|
chapDiscovery, err := getISCSIDiscoveryCHAPInfo(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
chapSession, err := getISCSISessionCHAPInfo(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &iscsiDiskMounter{
|
return &iscsiDiskMounter{
|
||||||
@ -140,16 +176,16 @@ func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UI
|
|||||||
podUID: podUID,
|
podUID: podUID,
|
||||||
VolName: spec.Name(),
|
VolName: spec.Name(),
|
||||||
Portals: bkportal,
|
Portals: bkportal,
|
||||||
Iqn: iscsi.IQN,
|
Iqn: iqn,
|
||||||
lun: lun,
|
lun: lun,
|
||||||
Iface: iface,
|
Iface: iface,
|
||||||
chap_discovery: iscsi.DiscoveryCHAPAuth,
|
chap_discovery: chapDiscovery,
|
||||||
chap_session: iscsi.SessionCHAPAuth,
|
chap_session: chapSession,
|
||||||
secret: secret,
|
secret: secret,
|
||||||
InitiatorName: initiatorName,
|
InitiatorName: initiatorName,
|
||||||
manager: manager,
|
manager: manager,
|
||||||
plugin: plugin},
|
plugin: plugin},
|
||||||
fsType: iscsi.FSType,
|
fsType: fsType,
|
||||||
readOnly: readOnly,
|
readOnly: readOnly,
|
||||||
mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec},
|
mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec},
|
||||||
exec: exec,
|
exec: exec,
|
||||||
@ -277,13 +313,87 @@ func portalMounter(portal string) string {
|
|||||||
return portal
|
return portal
|
||||||
}
|
}
|
||||||
|
|
||||||
func getVolumeSource(spec *volume.Spec) (*v1.ISCSIVolumeSource, bool, error) {
|
// get iSCSI volume info: readOnly and fstype
|
||||||
|
func getISCSIVolumeInfo(spec *volume.Spec) (bool, string, error) {
|
||||||
|
// for volume source, readonly is in volume spec
|
||||||
|
// for PV, readonly is in PV spec
|
||||||
if spec.Volume != nil && spec.Volume.ISCSI != nil {
|
if spec.Volume != nil && spec.Volume.ISCSI != nil {
|
||||||
return spec.Volume.ISCSI, spec.Volume.ISCSI.ReadOnly, nil
|
return spec.Volume.ISCSI.ReadOnly, spec.Volume.ISCSI.FSType, nil
|
||||||
} else if spec.PersistentVolume != nil &&
|
} else if spec.PersistentVolume != nil &&
|
||||||
spec.PersistentVolume.Spec.ISCSI != nil {
|
spec.PersistentVolume.Spec.ISCSI != nil {
|
||||||
return spec.PersistentVolume.Spec.ISCSI, spec.ReadOnly, nil
|
return spec.ReadOnly, spec.PersistentVolume.Spec.ISCSI.FSType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, false, fmt.Errorf("Spec does not reference an ISCSI volume type")
|
return false, "", fmt.Errorf("Spec does not reference an ISCSI volume type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// get iSCSI target info: target portal, portals, iqn, and lun
|
||||||
|
func getISCSITargetInfo(spec *volume.Spec) (string, []string, string, int32, error) {
|
||||||
|
if spec.Volume != nil && spec.Volume.ISCSI != nil {
|
||||||
|
return spec.Volume.ISCSI.TargetPortal, spec.Volume.ISCSI.Portals, spec.Volume.ISCSI.IQN, spec.Volume.ISCSI.Lun, nil
|
||||||
|
} else if spec.PersistentVolume != nil &&
|
||||||
|
spec.PersistentVolume.Spec.ISCSI != nil {
|
||||||
|
return spec.PersistentVolume.Spec.ISCSI.TargetPortal, spec.PersistentVolume.Spec.ISCSI.Portals, spec.PersistentVolume.Spec.ISCSI.IQN, spec.PersistentVolume.Spec.ISCSI.Lun, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil, "", 0, fmt.Errorf("Spec does not reference an ISCSI volume type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// get iSCSI initiator info: iface and initiator name
|
||||||
|
func getISCSIInitiatorInfo(spec *volume.Spec) (string, *string, error) {
|
||||||
|
if spec.Volume != nil && spec.Volume.ISCSI != nil {
|
||||||
|
return spec.Volume.ISCSI.ISCSIInterface, spec.Volume.ISCSI.InitiatorName, nil
|
||||||
|
} else if spec.PersistentVolume != nil &&
|
||||||
|
spec.PersistentVolume.Spec.ISCSI != nil {
|
||||||
|
return spec.PersistentVolume.Spec.ISCSI.ISCSIInterface, spec.PersistentVolume.Spec.ISCSI.InitiatorName, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil, fmt.Errorf("Spec does not reference an ISCSI volume type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// get iSCSI Discovery CHAP boolean
|
||||||
|
func getISCSIDiscoveryCHAPInfo(spec *volume.Spec) (bool, error) {
|
||||||
|
if spec.Volume != nil && spec.Volume.ISCSI != nil {
|
||||||
|
return spec.Volume.ISCSI.DiscoveryCHAPAuth, nil
|
||||||
|
} else if spec.PersistentVolume != nil &&
|
||||||
|
spec.PersistentVolume.Spec.ISCSI != nil {
|
||||||
|
return spec.PersistentVolume.Spec.ISCSI.DiscoveryCHAPAuth, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, fmt.Errorf("Spec does not reference an ISCSI volume type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// get iSCSI Session CHAP boolean
|
||||||
|
func getISCSISessionCHAPInfo(spec *volume.Spec) (bool, error) {
|
||||||
|
if spec.Volume != nil && spec.Volume.ISCSI != nil {
|
||||||
|
return spec.Volume.ISCSI.SessionCHAPAuth, nil
|
||||||
|
} else if spec.PersistentVolume != nil &&
|
||||||
|
spec.PersistentVolume.Spec.ISCSI != nil {
|
||||||
|
return spec.PersistentVolume.Spec.ISCSI.SessionCHAPAuth, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, fmt.Errorf("Spec does not reference an ISCSI volume type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// get iSCSI CHAP Secret info: secret name and namespace
|
||||||
|
func getISCSISecretNameAndNamespace(spec *volume.Spec, defaultSecretNamespace string) (string, string, error) {
|
||||||
|
if spec.Volume != nil && spec.Volume.ISCSI != nil {
|
||||||
|
if spec.Volume.ISCSI.SecretRef != nil {
|
||||||
|
return spec.Volume.ISCSI.SecretRef.Name, defaultSecretNamespace, nil
|
||||||
|
}
|
||||||
|
return "", "", nil
|
||||||
|
} else if spec.PersistentVolume != nil &&
|
||||||
|
spec.PersistentVolume.Spec.ISCSI != nil {
|
||||||
|
secretRef := spec.PersistentVolume.Spec.ISCSI.SecretRef
|
||||||
|
secretNs := defaultSecretNamespace
|
||||||
|
if secretRef != nil {
|
||||||
|
if len(secretRef.Namespace) != 0 {
|
||||||
|
secretNs = secretRef.Namespace
|
||||||
|
}
|
||||||
|
return secretRef.Name, secretNs, nil
|
||||||
|
}
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", "", fmt.Errorf("Spec does not reference an ISCSI volume type")
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ func TestPluginPersistentVolume(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Spec: v1.PersistentVolumeSpec{
|
Spec: v1.PersistentVolumeSpec{
|
||||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||||
ISCSI: &v1.ISCSIVolumeSource{
|
ISCSI: &v1.ISCSIPersistentVolumeSource{
|
||||||
TargetPortal: "127.0.0.1:3260",
|
TargetPortal: "127.0.0.1:3260",
|
||||||
IQN: "iqn.2014-12.server:storage.target01",
|
IQN: "iqn.2014-12.server:storage.target01",
|
||||||
FSType: "ext4",
|
FSType: "ext4",
|
||||||
@ -230,7 +230,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Spec: v1.PersistentVolumeSpec{
|
Spec: v1.PersistentVolumeSpec{
|
||||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||||
ISCSI: &v1.ISCSIVolumeSource{
|
ISCSI: &v1.ISCSIPersistentVolumeSource{
|
||||||
TargetPortal: "127.0.0.1:3260",
|
TargetPortal: "127.0.0.1:3260",
|
||||||
IQN: "iqn.2014-12.server:storage.target01",
|
IQN: "iqn.2014-12.server:storage.target01",
|
||||||
FSType: "ext4",
|
FSType: "ext4",
|
||||||
@ -283,3 +283,146 @@ func TestPortalMounter(t *testing.T) {
|
|||||||
t.Errorf("wrong portal: %s", portal)
|
t.Errorf("wrong portal: %s", portal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testcase struct {
|
||||||
|
name string
|
||||||
|
defaultNs string
|
||||||
|
spec *volume.Spec
|
||||||
|
// Expected return of the test
|
||||||
|
expectedName string
|
||||||
|
expectedNs string
|
||||||
|
expectedIface string
|
||||||
|
expectedError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSecretNameAndNamespaceForPV(t *testing.T) {
|
||||||
|
tests := []testcase{
|
||||||
|
{
|
||||||
|
name: "persistent volume source",
|
||||||
|
defaultNs: "default",
|
||||||
|
spec: &volume.Spec{
|
||||||
|
PersistentVolume: &v1.PersistentVolume{
|
||||||
|
Spec: v1.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||||
|
ISCSI: &v1.ISCSIPersistentVolumeSource{
|
||||||
|
TargetPortal: "127.0.0.1:3260",
|
||||||
|
IQN: "iqn.2014-12.server:storage.target01",
|
||||||
|
FSType: "ext4",
|
||||||
|
Lun: 0,
|
||||||
|
SecretRef: &v1.SecretReference{
|
||||||
|
Name: "name",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedName: "name",
|
||||||
|
expectedNs: "ns",
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "persistent volume source without namespace",
|
||||||
|
defaultNs: "default",
|
||||||
|
spec: &volume.Spec{
|
||||||
|
PersistentVolume: &v1.PersistentVolume{
|
||||||
|
Spec: v1.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||||
|
ISCSI: &v1.ISCSIPersistentVolumeSource{
|
||||||
|
TargetPortal: "127.0.0.1:3260",
|
||||||
|
IQN: "iqn.2014-12.server:storage.target01",
|
||||||
|
FSType: "ext4",
|
||||||
|
Lun: 0,
|
||||||
|
SecretRef: &v1.SecretReference{
|
||||||
|
Name: "name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedName: "name",
|
||||||
|
expectedNs: "default",
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pod volume source",
|
||||||
|
defaultNs: "default",
|
||||||
|
spec: &volume.Spec{
|
||||||
|
Volume: &v1.Volume{
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ISCSI: &v1.ISCSIVolumeSource{
|
||||||
|
TargetPortal: "127.0.0.1:3260",
|
||||||
|
IQN: "iqn.2014-12.server:storage.target01",
|
||||||
|
FSType: "ext4",
|
||||||
|
Lun: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedName: "",
|
||||||
|
expectedNs: "",
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testcase := range tests {
|
||||||
|
resultName, resultNs, err := getISCSISecretNameAndNamespace(testcase.spec, testcase.defaultNs)
|
||||||
|
if err != testcase.expectedError || resultName != testcase.expectedName || resultNs != testcase.expectedNs {
|
||||||
|
t.Errorf("%s failed: expected err=%v ns=%q name=%q, got %v/%q/%q", testcase.name, testcase.expectedError, testcase.expectedNs, testcase.expectedName,
|
||||||
|
err, resultNs, resultName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetISCSIInitiatorInfo(t *testing.T) {
|
||||||
|
tests := []testcase{
|
||||||
|
{
|
||||||
|
name: "persistent volume source",
|
||||||
|
spec: &volume.Spec{
|
||||||
|
PersistentVolume: &v1.PersistentVolume{
|
||||||
|
Spec: v1.PersistentVolumeSpec{
|
||||||
|
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||||
|
ISCSI: &v1.ISCSIPersistentVolumeSource{
|
||||||
|
TargetPortal: "127.0.0.1:3260",
|
||||||
|
IQN: "iqn.2014-12.server:storage.target01",
|
||||||
|
FSType: "ext4",
|
||||||
|
Lun: 0,
|
||||||
|
ISCSIInterface: "tcp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedIface: "tcp",
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pod volume source",
|
||||||
|
spec: &volume.Spec{
|
||||||
|
Volume: &v1.Volume{
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ISCSI: &v1.ISCSIVolumeSource{
|
||||||
|
TargetPortal: "127.0.0.1:3260",
|
||||||
|
IQN: "iqn.2014-12.server:storage.target01",
|
||||||
|
FSType: "ext4",
|
||||||
|
Lun: 0,
|
||||||
|
ISCSIInterface: "tcp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedIface: "tcp",
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testcase := range tests {
|
||||||
|
resultIface, _, err := getISCSIInitiatorInfo(testcase.spec)
|
||||||
|
if err != testcase.expectedError || resultIface != testcase.expectedIface {
|
||||||
|
t.Errorf("%s failed: expected err=%v iface=%s, got %v/%s", testcase.name, testcase.expectedError, testcase.expectedIface,
|
||||||
|
err, resultIface)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -402,7 +402,7 @@ type PersistentVolumeSource struct {
|
|||||||
// ISCSI represents an ISCSI Disk resource that is attached to a
|
// ISCSI represents an ISCSI Disk resource that is attached to a
|
||||||
// kubelet's host machine and then exposed to the pod. Provisioned by an admin.
|
// kubelet's host machine and then exposed to the pod. Provisioned by an admin.
|
||||||
// +optional
|
// +optional
|
||||||
ISCSI *ISCSIVolumeSource `json:"iscsi,omitempty" protobuf:"bytes,7,opt,name=iscsi"`
|
ISCSI *ISCSIPersistentVolumeSource `json:"iscsi,omitempty" protobuf:"bytes,7,opt,name=iscsi"`
|
||||||
// Cinder represents a cinder volume attached and mounted on kubelets host machine
|
// Cinder represents a cinder volume attached and mounted on kubelets host machine
|
||||||
// More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md
|
// More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md
|
||||||
// +optional
|
// +optional
|
||||||
@ -1236,14 +1236,15 @@ type NFSVolumeSource struct {
|
|||||||
// ISCSI volumes can only be mounted as read/write once.
|
// ISCSI volumes can only be mounted as read/write once.
|
||||||
// ISCSI volumes support ownership management and SELinux relabeling.
|
// ISCSI volumes support ownership management and SELinux relabeling.
|
||||||
type ISCSIVolumeSource struct {
|
type ISCSIVolumeSource struct {
|
||||||
// iSCSI target portal. The portal is either an IP or ip_addr:port if the port
|
// iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port
|
||||||
// is other than default (typically TCP ports 860 and 3260).
|
// is other than default (typically TCP ports 860 and 3260).
|
||||||
TargetPortal string `json:"targetPortal" protobuf:"bytes,1,opt,name=targetPortal"`
|
TargetPortal string `json:"targetPortal" protobuf:"bytes,1,opt,name=targetPortal"`
|
||||||
// Target iSCSI Qualified Name.
|
// Target iSCSI Qualified Name.
|
||||||
IQN string `json:"iqn" protobuf:"bytes,2,opt,name=iqn"`
|
IQN string `json:"iqn" protobuf:"bytes,2,opt,name=iqn"`
|
||||||
// iSCSI target lun number.
|
// iSCSI Target Lun number.
|
||||||
Lun int32 `json:"lun" protobuf:"varint,3,opt,name=lun"`
|
Lun int32 `json:"lun" protobuf:"varint,3,opt,name=lun"`
|
||||||
// Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport.
|
// iSCSI Interface Name that uses an iSCSI transport.
|
||||||
|
// Defaults to 'default' (tcp).
|
||||||
// +optional
|
// +optional
|
||||||
ISCSIInterface string `json:"iscsiInterface,omitempty" protobuf:"bytes,4,opt,name=iscsiInterface"`
|
ISCSIInterface string `json:"iscsiInterface,omitempty" protobuf:"bytes,4,opt,name=iscsiInterface"`
|
||||||
// Filesystem type of the volume that you want to mount.
|
// Filesystem type of the volume that you want to mount.
|
||||||
@ -1257,7 +1258,7 @@ type ISCSIVolumeSource struct {
|
|||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
// +optional
|
// +optional
|
||||||
ReadOnly bool `json:"readOnly,omitempty" protobuf:"varint,6,opt,name=readOnly"`
|
ReadOnly bool `json:"readOnly,omitempty" protobuf:"varint,6,opt,name=readOnly"`
|
||||||
// iSCSI target portal List. The portal is either an IP or ip_addr:port if the port
|
// iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port
|
||||||
// is other than default (typically TCP ports 860 and 3260).
|
// is other than default (typically TCP ports 860 and 3260).
|
||||||
// +optional
|
// +optional
|
||||||
Portals []string `json:"portals,omitempty" protobuf:"bytes,7,opt,name=portals"`
|
Portals []string `json:"portals,omitempty" protobuf:"bytes,7,opt,name=portals"`
|
||||||
@ -1267,10 +1268,56 @@ type ISCSIVolumeSource struct {
|
|||||||
// whether support iSCSI Session CHAP authentication
|
// whether support iSCSI Session CHAP authentication
|
||||||
// +optional
|
// +optional
|
||||||
SessionCHAPAuth bool `json:"chapAuthSession,omitempty" protobuf:"varint,11,opt,name=chapAuthSession"`
|
SessionCHAPAuth bool `json:"chapAuthSession,omitempty" protobuf:"varint,11,opt,name=chapAuthSession"`
|
||||||
// CHAP secret for iSCSI target and initiator authentication
|
// CHAP Secret for iSCSI target and initiator authentication
|
||||||
// +optional
|
// +optional
|
||||||
SecretRef *LocalObjectReference `json:"secretRef,omitempty" protobuf:"bytes,10,opt,name=secretRef"`
|
SecretRef *LocalObjectReference `json:"secretRef,omitempty" protobuf:"bytes,10,opt,name=secretRef"`
|
||||||
// Custom iSCSI initiator name.
|
// Custom iSCSI Initiator Name.
|
||||||
|
// If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface
|
||||||
|
// <target portal>:<volume name> will be created for the connection.
|
||||||
|
// +optional
|
||||||
|
InitiatorName *string `json:"initiatorName,omitempty" protobuf:"bytes,12,opt,name=initiatorName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ISCSIPersistentVolumeSource represents an ISCSI disk.
|
||||||
|
// ISCSI volumes can only be mounted as read/write once.
|
||||||
|
// ISCSI volumes support ownership management and SELinux relabeling.
|
||||||
|
type ISCSIPersistentVolumeSource struct {
|
||||||
|
// iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port
|
||||||
|
// is other than default (typically TCP ports 860 and 3260).
|
||||||
|
TargetPortal string `json:"targetPortal" protobuf:"bytes,1,opt,name=targetPortal"`
|
||||||
|
// Target iSCSI Qualified Name.
|
||||||
|
IQN string `json:"iqn" protobuf:"bytes,2,opt,name=iqn"`
|
||||||
|
// iSCSI Target Lun number.
|
||||||
|
Lun int32 `json:"lun" protobuf:"varint,3,opt,name=lun"`
|
||||||
|
// iSCSI Interface Name that uses an iSCSI transport.
|
||||||
|
// Defaults to 'default' (tcp).
|
||||||
|
// +optional
|
||||||
|
ISCSIInterface string `json:"iscsiInterface,omitempty" protobuf:"bytes,4,opt,name=iscsiInterface"`
|
||||||
|
// Filesystem type of the volume that you want to mount.
|
||||||
|
// Tip: Ensure that the filesystem type is supported by the host operating system.
|
||||||
|
// Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
|
||||||
|
// More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi
|
||||||
|
// TODO: how do we prevent errors in the filesystem from compromising the machine
|
||||||
|
// +optional
|
||||||
|
FSType string `json:"fsType,omitempty" protobuf:"bytes,5,opt,name=fsType"`
|
||||||
|
// ReadOnly here will force the ReadOnly setting in VolumeMounts.
|
||||||
|
// Defaults to false.
|
||||||
|
// +optional
|
||||||
|
ReadOnly bool `json:"readOnly,omitempty" protobuf:"varint,6,opt,name=readOnly"`
|
||||||
|
// iSCSI Target Portal List. The Portal is either an IP or ip_addr:port if the port
|
||||||
|
// is other than default (typically TCP ports 860 and 3260).
|
||||||
|
// +optional
|
||||||
|
Portals []string `json:"portals,omitempty" protobuf:"bytes,7,opt,name=portals"`
|
||||||
|
// whether support iSCSI Discovery CHAP authentication
|
||||||
|
// +optional
|
||||||
|
DiscoveryCHAPAuth bool `json:"chapAuthDiscovery,omitempty" protobuf:"varint,8,opt,name=chapAuthDiscovery"`
|
||||||
|
// whether support iSCSI Session CHAP authentication
|
||||||
|
// +optional
|
||||||
|
SessionCHAPAuth bool `json:"chapAuthSession,omitempty" protobuf:"varint,11,opt,name=chapAuthSession"`
|
||||||
|
// CHAP Secret for iSCSI target and initiator authentication
|
||||||
|
// +optional
|
||||||
|
SecretRef *SecretReference `json:"secretRef,omitempty" protobuf:"bytes,10,opt,name=secretRef"`
|
||||||
|
// Custom iSCSI Initiator Name.
|
||||||
// If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface
|
// If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface
|
||||||
// <target portal>:<volume name> will be created for the connection.
|
// <target portal>:<volume name> will be created for the connection.
|
||||||
// +optional
|
// +optional
|
||||||
|
Loading…
Reference in New Issue
Block a user