Merge pull request #16877 from anish/iscsi_iface

Auto commit by PR queue bot
pull/6/head
k8s-merge-robot 2015-12-09 11:52:37 -08:00
commit 5f7019ab9d
22 changed files with 27760 additions and 27554 deletions

View File

@ -12901,6 +12901,10 @@
"format": "int32",
"description": "iSCSI target lun number."
},
"iscsiInterface": {
"type": "string",
"description": "Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport."
},
"fsType": {
"type": "string",
"description": "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\". More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi"

View File

@ -3319,6 +3319,10 @@
"format": "int32",
"description": "iSCSI target lun number."
},
"iscsiInterface": {
"type": "string",
"description": "Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport."
},
"fsType": {
"type": "string",
"description": "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\". More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi"

View File

@ -2163,6 +2163,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">iscsiInterface</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Defaults to <em>default</em> (tcp). iSCSI interface name that uses an iSCSI transport.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">fsType</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">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". More info: <a href="http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi">http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
@ -4268,7 +4275,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</div>
<div id="footer">
<div id="footer-text">
Last updated 2015-12-01 22:09:32 UTC
Last updated 2015-12-07 03:51:23 UTC
</div>
</div>
</body>

View File

@ -1814,6 +1814,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">iscsiInterface</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Defaults to <em>default</em> (tcp). iSCSI interface name that uses an iSCSI transport.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">fsType</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">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". More info: <a href="http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi">http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
@ -6901,7 +6908,7 @@ The resulting set of endpoints can be viewed as:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2015-11-29 16:46:14 UTC
Last updated 2015-12-01 22:56:16 UTC
</div>
</div>
</body>

View File

@ -51,6 +51,8 @@ GCE does not provide preconfigured Fedora 21 image, so I set up the iSCSI target
Once you have installed iSCSI initiator and new Kubernetes, you can create a pod based on the example *iscsi.json*. In the pod JSON, you need to provide *targetPortal* (the iSCSI target's **IP** address and *port* if not the default port 3260), target's *iqn*, *lun*, and the type of the filesystem that has been created on the lun, and *readOnly* boolean. No initiator information is required.
If you want to use an iSCSI offload card or other open-iscsi transports besides tcp, setup an iSCSI interface and provide *iscsiInterface* in the pod JSON. The default name for an iscsi iface (open-iscsi parameter iface.iscsi\_ifacename) is in the format transport\_name.hwaddress when generated by iscsiadm. See [open-iscsi](http://www.open-iscsi.org/docs/README) or [openstack](http://docs.openstack.org/kilo/config-reference/content/iscsi-iface-config.html) for detailed configuration information.
**Note:** If you have followed the instructions in the links above you
may have partitioned the device, the iSCSI volume plugin does not
currently support partitions so format the device as one partition.

View File

@ -645,6 +645,7 @@ func deepCopy_api_ISCSIVolumeSource(in ISCSIVolumeSource, out *ISCSIVolumeSource
out.TargetPortal = in.TargetPortal
out.IQN = in.IQN
out.Lun = in.Lun
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
return nil

View File

@ -266,6 +266,12 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
c.Fuzz(t.Interface())
}
},
func(i *api.ISCSIVolumeSource, c fuzz.Continue) {
i.ISCSIInterface = c.RandString()
if i.ISCSIInterface == "" {
i.ISCSIInterface = "default"
}
},
func(d *api.DNSPolicy, c fuzz.Continue) {
policies := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault}
*d = policies[c.Rand.Intn(len(policies))]

File diff suppressed because it is too large Load Diff

View File

@ -449,6 +449,8 @@ type ISCSIVolumeSource struct {
IQN string `json:"iqn,omitempty"`
// Required: iSCSI target lun number
Lun int `json:"lun,omitempty"`
// Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport.
ISCSIInterface string `json:"iscsiInterface,omitempty"`
// Required: Filesystem type to mount.
// Must be a filesystem type supported by the host operating system.
// Ex. "ext4", "xfs", "ntfs"

View File

@ -919,6 +919,7 @@ func autoconvert_api_ISCSIVolumeSource_To_v1_ISCSIVolumeSource(in *api.ISCSIVolu
out.TargetPortal = in.TargetPortal
out.IQN = in.IQN
out.Lun = int32(in.Lun)
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
return nil
@ -3945,6 +3946,7 @@ func autoconvert_v1_ISCSIVolumeSource_To_api_ISCSIVolumeSource(in *ISCSIVolumeSo
out.TargetPortal = in.TargetPortal
out.IQN = in.IQN
out.Lun = int(in.Lun)
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
return nil

View File

@ -681,6 +681,7 @@ func deepCopy_v1_ISCSIVolumeSource(in ISCSIVolumeSource, out *ISCSIVolumeSource,
out.TargetPortal = in.TargetPortal
out.IQN = in.IQN
out.Lun = in.Lun
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
return nil

View File

@ -164,6 +164,11 @@ func addDefaultingFuncs() {
obj.Status.Phase = ClaimPending
}
},
func(obj *ISCSIVolumeSource) {
if obj.ISCSIInterface == "" {
obj.ISCSIInterface = "default"
}
},
func(obj *Endpoints) {
for i := range obj.Subsets {
ss := &obj.Subsets[i]

File diff suppressed because it is too large Load Diff

View File

@ -715,6 +715,8 @@ type ISCSIVolumeSource struct {
IQN string `json:"iqn"`
// iSCSI target lun number.
Lun int32 `json:"lun"`
// Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport.
ISCSIInterface string `json:"iscsiInterface,omitempty"`
// 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".

View File

@ -467,12 +467,13 @@ func (HostPathVolumeSource) SwaggerDoc() map[string]string {
}
var map_ISCSIVolumeSource = map[string]string{
"": "ISCSIVolumeSource describes an ISCSI Disk can only be mounted as read/write once.",
"targetPortal": "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).",
"iqn": "Target iSCSI Qualified Name.",
"lun": "iSCSI target lun number.",
"fsType": "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\". More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi",
"readOnly": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.",
"": "ISCSIVolumeSource describes an ISCSI Disk can only be mounted as read/write once.",
"targetPortal": "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).",
"iqn": "Target iSCSI Qualified Name.",
"lun": "iSCSI target lun number.",
"iscsiInterface": "Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport.",
"fsType": "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\". More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi",
"readOnly": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.",
}
func (ISCSIVolumeSource) SwaggerDoc() map[string]string {

View File

@ -348,6 +348,7 @@ func deepCopy_api_ISCSIVolumeSource(in api.ISCSIVolumeSource, out *api.ISCSIVolu
out.TargetPortal = in.TargetPortal
out.IQN = in.IQN
out.Lun = in.Lun
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
return nil

View File

@ -490,6 +490,7 @@ func autoconvert_api_ISCSIVolumeSource_To_v1_ISCSIVolumeSource(in *api.ISCSIVolu
out.TargetPortal = in.TargetPortal
out.IQN = in.IQN
out.Lun = int32(in.Lun)
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
return nil
@ -1550,6 +1551,7 @@ func autoconvert_v1_ISCSIVolumeSource_To_api_ISCSIVolumeSource(in *v1.ISCSIVolum
out.TargetPortal = in.TargetPortal
out.IQN = in.IQN
out.Lun = int(in.Lun)
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
return nil

View File

@ -384,6 +384,7 @@ func deepCopy_v1_ISCSIVolumeSource(in v1.ISCSIVolumeSource, out *v1.ISCSIVolumeS
out.TargetPortal = in.TargetPortal
out.IQN = in.IQN
out.Lun = in.Lun
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
return nil

View File

@ -583,9 +583,10 @@ func printISCSIVolumeSource(iscsi *api.ISCSIVolumeSource, out io.Writer) {
" TargetPortal:\t%v\n"+
" IQN:\t%v\n"+
" Lun:\t%v\n"+
" ISCSIInterface\t%v\n"+
" FSType:\t%v\n"+
" ReadOnly:\t%v\n",
iscsi.TargetPortal, iscsi.IQN, iscsi.Lun, iscsi.FSType, iscsi.ReadOnly)
iscsi.TargetPortal, iscsi.IQN, iscsi.Lun, iscsi.ISCSIInterface, iscsi.FSType, iscsi.ReadOnly)
}
func printGlusterfsVolumeSource(glusterfs *api.GlusterfsVolumeSource, out io.Writer) {

View File

@ -97,6 +97,8 @@ func (plugin *iscsiPlugin) newBuilderInternal(spec *volume.Spec, podUID types.UI
lun := strconv.Itoa(iscsi.Lun)
portal := portalBuilder(iscsi.TargetPortal)
iface := iscsi.ISCSIInterface
return &iscsiDiskBuilder{
iscsiDisk: &iscsiDisk{
podUID: podUID,
@ -104,6 +106,7 @@ func (plugin *iscsiPlugin) newBuilderInternal(spec *volume.Spec, podUID types.UI
portal: portal,
iqn: iscsi.IQN,
lun: lun,
iface: iface,
manager: manager,
plugin: plugin},
fsType: iscsi.FSType,
@ -140,6 +143,7 @@ type iscsiDisk struct {
portal string
iqn string
lun string
iface string
plugin *iscsiPlugin
// Utility interface that provides API calls to the provider to attach/detach disks.
manager diskManager

View File

@ -21,6 +21,7 @@ import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
"time"
@ -30,9 +31,26 @@ import (
)
// stat a path, if not exists, retry maxRetries times
func waitForPathToExist(devicePath string, maxRetries int) bool {
// when iscsi transports other than default are used, use glob instead as pci id of device is unknown
type StatFunc func(string) (os.FileInfo, error)
type GlobFunc func(string) ([]string, error)
func waitForPathToExist(devicePath string, maxRetries int, deviceInterface string) bool {
// This makes unit testing a lot easier
return waitForPathToExistInternal(devicePath, maxRetries, deviceInterface, os.Stat, filepath.Glob)
}
func waitForPathToExistInternal(devicePath string, maxRetries int, deviceInterface string, osStat StatFunc, filepathGlob GlobFunc) bool {
for i := 0; i < maxRetries; i++ {
_, err := os.Stat(devicePath)
var err error
if deviceInterface == "default" {
_, err = osStat(devicePath)
} else {
fpath, _ := filepathGlob(devicePath)
if fpath == nil {
err = os.ErrNotExist
}
}
if err == nil {
return true
}
@ -80,22 +98,27 @@ func (util *ISCSIUtil) MakeGlobalPDName(iscsi iscsiDisk) string {
}
func (util *ISCSIUtil) AttachDisk(b iscsiDiskBuilder) error {
devicePath := strings.Join([]string{"/dev/disk/by-path/ip", b.portal, "iscsi", b.iqn, "lun", b.lun}, "-")
exist := waitForPathToExist(devicePath, 1)
var devicePath string
if b.iface == "default" {
devicePath = strings.Join([]string{"/dev/disk/by-path/ip", b.portal, "iscsi", b.iqn, "lun", b.lun}, "-")
} else {
devicePath = strings.Join([]string{"/dev/disk/by-path/pci", "*", "ip", b.portal, "iscsi", b.iqn, "lun", b.lun}, "-")
}
exist := waitForPathToExist(devicePath, 1, b.iface)
if exist == false {
// discover iscsi target
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "discovery", "-t", "sendtargets", "-p", b.portal})
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "discovery", "-t", "sendtargets", "-p", b.portal, "-I", b.iface})
if err != nil {
glog.Errorf("iscsi: failed to sendtargets to portal %s error: %s", b.portal, string(out))
return err
}
// login to iscsi target
out, err = b.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", b.portal, "-T", b.iqn, "--login"})
out, err = b.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", b.portal, "-T", b.iqn, "-I", b.iface, "--login"})
if err != nil {
glog.Errorf("iscsi: failed to attach disk:Error: %s (%v)", string(out), err)
return err
}
exist = waitForPathToExist(devicePath, 10)
exist = waitForPathToExist(devicePath, 10, b.iface)
if !exist {
return errors.New("Could not attach disk: Timeout after 10s")
}

View File

@ -17,6 +17,8 @@ limitations under the License.
package iscsi
import (
"os"
"path/filepath"
"testing"
"k8s.io/kubernetes/pkg/util/mount"
@ -74,3 +76,35 @@ func TestExtractPortalAndIqn(t *testing.T) {
t.Errorf("extractPortalAndIqn: got %v %s %s", err, portal, iqn)
}
}
func fakeOsStat(devicePath string) (fi os.FileInfo, err error) {
var cmd os.FileInfo
return cmd, nil
}
func fakeFilepathGlob(devicePath string) (globs []string, err error) {
return []string{devicePath}, nil
}
func TestWaitForPathToExist(t *testing.T) {
devicePath := []string{"/dev/disk/by-path/ip-127.0.0.1:3260-iqn.2014-12.com.example:test.tgt00-lun-0",
"/dev/disk/by-path/pci-0000:00:00.0-ip-127.0.0.1:3260-iqn.2014-12.com.example:test.tgt00-lun-0"}
exist := waitForPathToExistInternal(devicePath[0], 1, "default", fakeOsStat, filepath.Glob)
if exist == false {
t.Errorf("waitForPathToExist: could not find path %s", devicePath[0])
}
exist = waitForPathToExistInternal(devicePath[0], 1, "fake_iface", fakeOsStat, filepath.Glob)
if exist != false {
t.Errorf("waitForPathToExist: wrong code path called for %s", devicePath[0])
}
exist = waitForPathToExistInternal(devicePath[1], 1, "fake_iface", os.Stat, fakeFilepathGlob)
if exist == false {
t.Errorf("waitForPathToExist: could not find path %s", devicePath[1])
}
exist = waitForPathToExistInternal(devicePath[1], 1, "default", os.Stat, fakeFilepathGlob)
if exist != false {
t.Errorf("waitForPathToExist: wrong code path called for %s", devicePath[1])
}
}