mirror of https://github.com/k3s-io/k3s
commit
5f7019ab9d
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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".
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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])
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue