diff --git a/pkg/api/types.go b/pkg/api/types.go index 83ffbc7e970..ee1c14b3133 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -228,6 +228,9 @@ type PersistentVolumeSource struct { NFS *NFSVolumeSource `json:"nfs"` // RBD represents a Rados Block Device mount on the host that shares a pod's lifetime RBD *RBDVolumeSource `json:"rbd"` + // ISCSIVolumeSource represents an ISCSI resource that is attached to a + // kubelet's host machine and then exposed to the pod. + ISCSI *ISCSIVolumeSource `json:"iscsi"` } type PersistentVolumeClaimVolumeSource struct { diff --git a/pkg/api/v1/conversion_generated.go b/pkg/api/v1/conversion_generated.go index 03127b35e51..6911c3ba1a8 100644 --- a/pkg/api/v1/conversion_generated.go +++ b/pkg/api/v1/conversion_generated.go @@ -1311,6 +1311,14 @@ func convert_api_PersistentVolumeSource_To_v1_PersistentVolumeSource(in *api.Per } else { out.RBD = nil } + if in.ISCSI != nil { + out.ISCSI = new(ISCSIVolumeSource) + if err := convert_api_ISCSIVolumeSource_To_v1_ISCSIVolumeSource(in.ISCSI, out.ISCSI, s); err != nil { + return err + } + } else { + out.ISCSI = nil + } return nil } @@ -3567,6 +3575,14 @@ func convert_v1_PersistentVolumeSource_To_api_PersistentVolumeSource(in *Persist } else { out.RBD = nil } + if in.ISCSI != nil { + out.ISCSI = new(api.ISCSIVolumeSource) + if err := convert_v1_ISCSIVolumeSource_To_api_ISCSIVolumeSource(in.ISCSI, out.ISCSI, s); err != nil { + return err + } + } else { + out.ISCSI = nil + } return nil } diff --git a/pkg/api/v1/types.go b/pkg/api/v1/types.go index 2a9d38cc93b..472d991192f 100644 --- a/pkg/api/v1/types.go +++ b/pkg/api/v1/types.go @@ -253,6 +253,9 @@ type PersistentVolumeSource struct { NFS *NFSVolumeSource `json:"nfs,omitempty" description:"NFS volume resource provisioned by an admin"` // RBD represents a Rados Block Device mount on the host that shares a pod's lifetime RBD *RBDVolumeSource `json:"rbd" description:"rados block volume that will be mounted on the host machine"` + // ISCSI represents an ISCSI Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + ISCSI *ISCSIVolumeSource `json:"iscsi" description:"an iSCSI disk resource provisioned by an admin"` } type PersistentVolume struct { diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index 28efed20e50..e70b90184ee 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -156,6 +156,9 @@ type PersistentVolumeSource struct { NFS *NFSVolumeSource `json:"nfs" description:"NFS volume resource provisioned by an admin"` // RBD represents a Rados Block Device mount on the host that shares a pod's lifetime RBD *RBDVolumeSource `json:"rbd" description:"rados block volume that will be mounted on the host machine"` + // ISCSI represents an ISCSI Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + ISCSI *ISCSIVolumeSource `json:"iscsi" description:"an iSCSI disk resource provisioned by an admin"` } type PersistentVolumeClaimVolumeSource struct { diff --git a/pkg/api/v1beta2/types.go b/pkg/api/v1beta2/types.go index 4bfc4ec46c3..5fb43357846 100644 --- a/pkg/api/v1beta2/types.go +++ b/pkg/api/v1beta2/types.go @@ -113,6 +113,9 @@ type PersistentVolumeSource struct { NFS *NFSVolumeSource `json:"nfs" description:"NFS volume resource provisioned by an admin"` // RBD represents a Rados Block Device mount on the host that shares a pod's lifetime RBD *RBDVolumeSource `json:"rbd" description:"rados block volume that will be mounted on the host machine"` + // ISCSI represents an ISCSI Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + ISCSI *ISCSIVolumeSource `json:"iscsi" description:"an iSCSI disk resource provisioned by an admin"` } type PersistentVolumeClaimVolumeSource struct { diff --git a/pkg/api/v1beta3/conversion_generated.go b/pkg/api/v1beta3/conversion_generated.go index ac9d881b7e9..bb504d1a220 100644 --- a/pkg/api/v1beta3/conversion_generated.go +++ b/pkg/api/v1beta3/conversion_generated.go @@ -1218,6 +1218,14 @@ func convert_api_PersistentVolumeSource_To_v1beta3_PersistentVolumeSource(in *ap } else { out.RBD = nil } + if in.ISCSI != nil { + out.ISCSI = new(ISCSIVolumeSource) + if err := convert_api_ISCSIVolumeSource_To_v1beta3_ISCSIVolumeSource(in.ISCSI, out.ISCSI, s); err != nil { + return err + } + } else { + out.ISCSI = nil + } return nil } @@ -3407,6 +3415,14 @@ func convert_v1beta3_PersistentVolumeSource_To_api_PersistentVolumeSource(in *Pe } else { out.RBD = nil } + if in.ISCSI != nil { + out.ISCSI = new(api.ISCSIVolumeSource) + if err := convert_v1beta3_ISCSIVolumeSource_To_api_ISCSIVolumeSource(in.ISCSI, out.ISCSI, s); err != nil { + return err + } + } else { + out.ISCSI = nil + } return nil } diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index 1f28ef0893d..d945838b2ae 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -253,6 +253,9 @@ type PersistentVolumeSource struct { NFS *NFSVolumeSource `json:"nfs,omitempty" description:"NFS volume resource provisioned by an admin"` // RBD represents a Rados Block Device mount on the host that shares a pod's lifetime RBD *RBDVolumeSource `json:"rbd" description:"rados block volume that will be mounted on the host machine"` + // ISCSI represents an ISCSI Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + ISCSI *ISCSIVolumeSource `json:"iscsi" description:"an iSCSI disk resource provisioned by an admin"` } type PersistentVolume struct { diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index c5dc49f65c4..9e18919623e 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -518,6 +518,10 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) errs.ValidationErrorList numVolumes++ allErrs = append(allErrs, validateRBD(pv.Spec.RBD).Prefix("rbd")...) } + if pv.Spec.ISCSI != nil { + numVolumes++ + allErrs = append(allErrs, validateISCSIVolumeSource(pv.Spec.ISCSI).Prefix("iscsi")...) + } if numVolumes != 1 { allErrs = append(allErrs, errs.NewFieldInvalid("", pv.Spec.PersistentVolumeSource, "exactly 1 volume type is required")) } diff --git a/pkg/volume/iscsi/iscsi.go b/pkg/volume/iscsi/iscsi.go index 3695642b7fe..bfc8e5986c9 100644 --- a/pkg/volume/iscsi/iscsi.go +++ b/pkg/volume/iscsi/iscsi.go @@ -53,9 +53,11 @@ func (plugin *ISCSIPlugin) Name() string { } func (plugin *ISCSIPlugin) CanSupport(spec *volume.Spec) bool { - if spec.VolumeSource.ISCSI == nil { + if spec.VolumeSource.ISCSI == nil && spec.PersistentVolumeSource.ISCSI == nil { return false } + // TODO: turn this into a func so CanSupport can be unit tested without + // having to make system calls // see if iscsiadm is there _, err := plugin.execCommand("iscsiadm", []string{"-h"}) if err == nil { diff --git a/pkg/volume/iscsi/iscsi_test.go b/pkg/volume/iscsi/iscsi_test.go index b3cdf9f494a..aacbf00fef5 100644 --- a/pkg/volume/iscsi/iscsi_test.go +++ b/pkg/volume/iscsi/iscsi_test.go @@ -39,6 +39,28 @@ func TestCanSupport(t *testing.T) { } } +func TestGetAccessModes(t *testing.T) { + plugMgr := volume.VolumePluginMgr{} + plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", nil, nil)) + + plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/iscsi") + if err != nil { + t.Errorf("Can't find the plugin by name") + } + if !contains(plug.GetAccessModes(), api.ReadWriteOnce) || !contains(plug.GetAccessModes(), api.ReadOnlyMany) { + t.Errorf("Expected two AccessModeTypes: %s and %s", api.ReadWriteOnce, api.ReadOnlyMany) + } +} + +func contains(modes []api.PersistentVolumeAccessMode, mode api.PersistentVolumeAccessMode) bool { + for _, m := range modes { + if m == mode { + return true + } + } + return false +} + type fakeDiskManager struct { attachCalled bool detachCalled bool