Merge pull request #39928 from humblec/iscsi-multipath-backuptp

Automatic merge from submit-queue

Add mulitpath support to iscsi plugin

#issue https://github.com/kubernetes/kubernetes/issues/39345
Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
This commit is contained in:
Kubernetes Submit Queue 2017-02-13 12:18:55 -08:00 committed by GitHub
commit a75b61d7a3
25 changed files with 1063 additions and 800 deletions

View File

@ -36654,6 +36654,13 @@
"type": "integer",
"format": "int32"
},
"portals": {
"description": "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).",
"type": "array",
"items": {
"type": "string"
}
},
"readOnly": {
"description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.",
"type": "boolean"

View File

@ -1645,7 +1645,8 @@
"required": [
"targetPortal",
"iqn",
"lun"
"lun",
"portals"
],
"properties": {
"targetPortal": {
@ -1672,6 +1673,13 @@
"readOnly": {
"type": "boolean",
"description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false."
},
"portals": {
"type": "array",
"items": {
"type": "string"
},
"description": "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)."
}
}
},

View File

@ -1650,7 +1650,8 @@
"required": [
"targetPortal",
"iqn",
"lun"
"lun",
"portals"
],
"properties": {
"targetPortal": {
@ -1677,6 +1678,13 @@
"readOnly": {
"type": "boolean",
"description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false."
},
"portals": {
"type": "array",
"items": {
"type": "string"
},
"description": "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)."
}
}
},

View File

@ -7052,7 +7052,8 @@
"required": [
"targetPortal",
"iqn",
"lun"
"lun",
"portals"
],
"properties": {
"targetPortal": {
@ -7079,6 +7080,13 @@
"readOnly": {
"type": "boolean",
"description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false."
},
"portals": {
"type": "array",
"items": {
"type": "string"
},
"description": "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)."
}
}
},

View File

@ -17847,7 +17847,8 @@
"required": [
"targetPortal",
"iqn",
"lun"
"lun",
"portals"
],
"properties": {
"targetPortal": {
@ -17874,6 +17875,13 @@
"readOnly": {
"type": "boolean",
"description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false."
},
"portals": {
"type": "array",
"items": {
"type": "string"
},
"description": "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)."
}
}
},

View File

@ -2497,6 +2497,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">portals</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">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).</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
@ -5074,7 +5081,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-02-02 23:51:07 UTC
Last updated 2017-02-06 11:50:05 UTC
</div>
</div>
</body>

View File

@ -2408,6 +2408,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">portals</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">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).</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
@ -5006,7 +5013,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-02-02 23:51:26 UTC
Last updated 2017-02-06 11:50:30 UTC
</div>
</div>
</body>

View File

@ -2239,6 +2239,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">portals</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">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).</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
@ -7297,7 +7304,7 @@ Both these may change in the future. Incoming requests are matched against the h
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-02-02 23:51:41 UTC
Last updated 2017-02-06 11:50:48 UTC
</div>
</div>
</body>

View File

@ -2420,6 +2420,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">portals</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">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).</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
@ -9254,7 +9261,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-02-02 23:51:00 UTC
Last updated 2017-02-06 11:49:57 UTC
</div>
</div>
</body>

View File

@ -18,7 +18,7 @@ If there isn't one in place then it is possible to setup a software version on L
## Creating the pod with iSCSI persistent storage
Once you have configured the iSCSI initiator, you can create a pod based on the example *iscsi.yaml*. In the pod YAML, 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.
Once you have configured the iSCSI initiator, you can create a pod based on the example *iscsi.yaml*. In the pod YAML, 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 have more than one target portals for a single IQN, you can mention other portal IPs in *portals* field.
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 YAML. 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.
@ -48,19 +48,23 @@ For a non mpio device the output should look like the following
```console
# mount |grep kub
/dev/sdb on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.15:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-0 type ext4 (ro,relatime,data=ordered)
/dev/sdb on /var/lib/kubelet/pods/f527ca5b-6d87-11e5-aa7e-080027ff6387/volumes/kubernetes.io~iscsi/iscsipd-ro type ext4 (ro,relatime,data=ordered)
/dev/sdc on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.15:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-1 type ext4 (rw,relatime,data=ordered)
/dev/sdb on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.15:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-0 type ext4 (rw,relatime,data=ordered)
/dev/sdb on /var/lib/kubelet/pods/f527ca5b-6d87-11e5-aa7e-080027ff6387/volumes/kubernetes.io~iscsi/iscsipd-rw type ext4 (ro,relatime,data=ordered)
/dev/sdc on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.16:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-0 type ext4 (rw,relatime,data=ordered)
/dev/sdc on /var/lib/kubelet/pods/f527ca5b-6d87-11e5-aa7e-080027ff6387/volumes/kubernetes.io~iscsi/iscsipd-rw type ext4 (rw,relatime,data=ordered)
/dev/sdd on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.17:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-0 type ext4 (rw,relatime,data=ordered)
/dev/sdd on /var/lib/kubelet/pods/f527ca5b-6d87-11e5-aa7e-080027ff6387/volumes/kubernetes.io~iscsi/iscsipd-rw type ext4 (rw,relatime,data=ordered)
```
And for a node with mpio enabled the expected output would be similar to the following
```console
# mount |grep kub
/dev/mapper/mpatha on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.15:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-0 type ext4 (ro,relatime,data=ordered)
/dev/mapper/mpatha on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.15:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-0 type ext4 (rw,relatime,data=ordered)
/dev/mapper/mpatha on /var/lib/kubelet/pods/f527ca5b-6d87-11e5-aa7e-080027ff6387/volumes/kubernetes.io~iscsi/iscsipd-ro type ext4 (ro,relatime,data=ordered)
/dev/mapper/mpathb on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.15:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-1 type ext4 (rw,relatime,data=ordered)
/dev/mapper/mpathb on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.16:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-0 type ext4 (rw,relatime,data=ordered)
/dev/mapper/mpathb on /var/lib/kubelet/pods/f527ca5b-6d87-11e5-aa7e-080027ff6387/volumes/kubernetes.io~iscsi/iscsipd-rw type ext4 (rw,relatime,data=ordered)
/dev/mapper/mpathc on /var/lib/kubelet/plugins/kubernetes.io/iscsi/10.0.2.17:3260-iqn.2001-04.com.example:storage.kube.sys1.xyz-lun-0 type ext4 (rw,relatime,data=ordered)
/dev/mapper/mpathb on /var/lib/kubelet/pods/f527ca5b-6d87-11e5-aa7e-080027ff6387/volumes/kubernetes.io~iscsi/iscsipd-rw type ext4 (rw,relatime,data=ordered)
```
@ -70,7 +74,6 @@ If you ssh to that machine, you can run `docker ps` to see the actual pod.
```console
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f855336407f4 kubernetes/pause "/pause" 6 minutes ago Up 6 minutes k8s_iscsipd-ro.d130ec3e_iscsipd_default_f527ca5b-6d87-11e5-aa7e-080027ff6387_5409a4cb
3b8a772515d2 kubernetes/pause "/pause" 6 minutes ago Up 6 minutes k8s_iscsipd-rw.ed58ec4e_iscsipd_default_f527ca5b-6d87-11e5-aa7e-080027ff6387_d25592c5
```

View File

@ -5,28 +5,17 @@ metadata:
name: iscsipd
spec:
containers:
- name: iscsipd-ro
image: kubernetes/pause
volumeMounts:
- mountPath: "/mnt/iscsipd"
name: iscsipd-ro
- name: iscsipd-rw
image: kubernetes/pause
volumeMounts:
- mountPath: "/mnt/iscsipd"
name: iscsipd-rw
volumes:
- name: iscsipd-ro
- name: iscsipd-rw
iscsi:
targetPortal: 10.0.2.15:3260
portals: ['10.0.2.16:3260', '10.0.2.17:3260']
iqn: iqn.2001-04.com.example:storage.kube.sys1.xyz
lun: 0
fsType: ext4
readOnly: true
- name: iscsipd-rw
iscsi:
targetPortal: 10.0.2.15:3260
iqn: iqn.2001-04.com.example:storage.kube.sys1.xyz
lun: 1
fsType: ext4
readOnly: false

View File

@ -12038,6 +12038,13 @@
"type": "integer",
"format": "int32"
},
"portals": {
"description": "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).",
"type": "array",
"items": {
"type": "string"
}
},
"readOnly": {
"description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.",
"type": "boolean"

View File

@ -4569,7 +4569,8 @@
"type": "array",
"items": {
"$ref": "v1.Container"
}
},
"description": "List of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, or Liveness probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/containers"
},
"containers": {
"type": "array",
@ -4931,7 +4932,8 @@
"required": [
"targetPortal",
"iqn",
"lun"
"lun",
"portals"
],
"properties": {
"targetPortal": {
@ -4958,6 +4960,12 @@
"readOnly": {
"type": "boolean",
"description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false."
},
"portals": {
"type": "array",
"items": {
"type": "string"
}
}
}
},

View File

@ -625,6 +625,10 @@ type ISCSIVolumeSource struct {
// the ReadOnly setting in VolumeMounts.
// +optional
ReadOnly bool
// Required: 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
}
// Represents a Fibre Channel volume.

File diff suppressed because it is too large Load Diff

View File

@ -1179,6 +1179,11 @@ message ISCSIVolumeSource {
// Defaults to false.
// +optional
optional bool readOnly = 6;
// 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
repeated string portals = 7;
}
// Maps a string key to a path within a volume.

View File

@ -14833,7 +14833,7 @@ func (x *ISCSIVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [6]bool
var yyq2 [7]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[3] = x.ISCSIInterface != ""
@ -14841,9 +14841,9 @@ func (x *ISCSIVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
yyq2[5] = x.ReadOnly != false
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(6)
r.EncodeArrayStart(7)
} else {
yynn2 = 3
yynn2 = 4
for _, b := range yyq2 {
if b {
yynn2++
@ -14984,6 +14984,33 @@ func (x *ISCSIVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if x.Portals == nil {
r.EncodeNil()
} else {
yym22 := z.EncBinary()
_ = yym22
if false {
} else {
z.F.EncSliceStringV(x.Portals, false, e)
}
}
} else {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("portals"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
if x.Portals == nil {
r.EncodeNil()
} else {
yym23 := z.EncBinary()
_ = yym23
if false {
} else {
z.F.EncSliceStringV(x.Portals, false, e)
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
@ -15117,6 +15144,18 @@ func (x *ISCSIVolumeSource) codecDecodeSelfFromMap(l int, d *codec1978.Decoder)
*((*bool)(yyv14)) = r.DecodeBool()
}
}
case "portals":
if r.TryDecodeAsNil() {
x.Portals = nil
} else {
yyv16 := &x.Portals
yym17 := z.DecBinary()
_ = yym17
if false {
} else {
z.F.DecSliceStringX(yyv16, false, d)
}
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
@ -15128,16 +15167,16 @@ func (x *ISCSIVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj16 int
var yyb16 bool
var yyhl16 bool = l >= 0
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
var yyj18 int
var yyb18 bool
var yyhl18 bool = l >= 0
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb16 = r.CheckBreak()
yyb18 = r.CheckBreak()
}
if yyb16 {
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -15145,29 +15184,7 @@ func (x *ISCSIVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
if r.TryDecodeAsNil() {
x.TargetPortal = ""
} else {
yyv17 := &x.TargetPortal
yym18 := z.DecBinary()
_ = yym18
if false {
} else {
*((*string)(yyv17)) = r.DecodeString()
}
}
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
} else {
yyb16 = r.CheckBreak()
}
if yyb16 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.IQN = ""
} else {
yyv19 := &x.IQN
yyv19 := &x.TargetPortal
yym20 := z.DecBinary()
_ = yym20
if false {
@ -15175,13 +15192,35 @@ func (x *ISCSIVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
*((*string)(yyv19)) = r.DecodeString()
}
}
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb16 = r.CheckBreak()
yyb18 = r.CheckBreak()
}
if yyb16 {
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.IQN = ""
} else {
yyv21 := &x.IQN
yym22 := z.DecBinary()
_ = yym22
if false {
} else {
*((*string)(yyv21)) = r.DecodeString()
}
}
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb18 = r.CheckBreak()
}
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -15189,21 +15228,21 @@ func (x *ISCSIVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
if r.TryDecodeAsNil() {
x.Lun = 0
} else {
yyv21 := &x.Lun
yym22 := z.DecBinary()
_ = yym22
yyv23 := &x.Lun
yym24 := z.DecBinary()
_ = yym24
if false {
} else {
*((*int32)(yyv21)) = int32(r.DecodeInt(32))
*((*int32)(yyv23)) = int32(r.DecodeInt(32))
}
}
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb16 = r.CheckBreak()
yyb18 = r.CheckBreak()
}
if yyb16 {
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -15211,29 +15250,7 @@ func (x *ISCSIVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
if r.TryDecodeAsNil() {
x.ISCSIInterface = ""
} else {
yyv23 := &x.ISCSIInterface
yym24 := z.DecBinary()
_ = yym24
if false {
} else {
*((*string)(yyv23)) = r.DecodeString()
}
}
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
} else {
yyb16 = r.CheckBreak()
}
if yyb16 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.FSType = ""
} else {
yyv25 := &x.FSType
yyv25 := &x.ISCSIInterface
yym26 := z.DecBinary()
_ = yym26
if false {
@ -15241,13 +15258,35 @@ func (x *ISCSIVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
*((*string)(yyv25)) = r.DecodeString()
}
}
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb16 = r.CheckBreak()
yyb18 = r.CheckBreak()
}
if yyb16 {
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.FSType = ""
} else {
yyv27 := &x.FSType
yym28 := z.DecBinary()
_ = yym28
if false {
} else {
*((*string)(yyv27)) = r.DecodeString()
}
}
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb18 = r.CheckBreak()
}
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -15255,26 +15294,48 @@ func (x *ISCSIVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
if r.TryDecodeAsNil() {
x.ReadOnly = false
} else {
yyv27 := &x.ReadOnly
yym28 := z.DecBinary()
_ = yym28
yyv29 := &x.ReadOnly
yym30 := z.DecBinary()
_ = yym30
if false {
} else {
*((*bool)(yyv27)) = r.DecodeBool()
*((*bool)(yyv29)) = r.DecodeBool()
}
}
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb18 = r.CheckBreak()
}
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Portals = nil
} else {
yyv31 := &x.Portals
yym32 := z.DecBinary()
_ = yym32
if false {
} else {
z.F.DecSliceStringX(yyv31, false, d)
}
}
for {
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb16 = r.CheckBreak()
yyb18 = r.CheckBreak()
}
if yyb16 {
if yyb18 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj16-1, "")
z.DecStructFieldNotFound(yyj18-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}

View File

@ -988,6 +988,10 @@ type ISCSIVolumeSource struct {
// 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" protobuf:"bytes,7,opt,name=portals"`
}
// Represents a Fibre Channel volume.

View File

@ -637,6 +637,7 @@ var map_ISCSIVolumeSource = map[string]string{
"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\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://kubernetes.io/docs/user-guide/volumes#iscsi",
"readOnly": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.",
"portals": "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).",
}
func (ISCSIVolumeSource) SwaggerDoc() map[string]string {

View File

@ -1613,6 +1613,7 @@ func autoConvert_v1_ISCSIVolumeSource_To_api_ISCSIVolumeSource(in *ISCSIVolumeSo
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
out.Portals = *(*[]string)(unsafe.Pointer(&in.Portals))
return nil
}
@ -1627,6 +1628,7 @@ func autoConvert_api_ISCSIVolumeSource_To_v1_ISCSIVolumeSource(in *api.ISCSIVolu
out.ISCSIInterface = in.ISCSIInterface
out.FSType = in.FSType
out.ReadOnly = in.ReadOnly
out.Portals = *(*[]string)(unsafe.Pointer(&in.Portals))
return nil
}

View File

@ -1140,6 +1140,11 @@ func DeepCopy_v1_ISCSIVolumeSource(in interface{}, out interface{}, c *conversio
in := in.(*ISCSIVolumeSource)
out := out.(*ISCSIVolumeSource)
*out = *in
if in.Portals != nil {
in, out := &in.Portals, &out.Portals
*out = make([]string, len(*in))
copy(*out, *in)
}
return nil
}
}
@ -1885,7 +1890,9 @@ func DeepCopy_v1_PersistentVolumeSource(in interface{}, out interface{}, c *conv
if in.ISCSI != nil {
in, out := &in.ISCSI, &out.ISCSI
*out = new(ISCSIVolumeSource)
**out = **in
if err := DeepCopy_v1_ISCSIVolumeSource(*in, *out, c); err != nil {
return err
}
}
if in.Cinder != nil {
in, out := &in.Cinder, &out.Cinder
@ -3155,7 +3162,9 @@ func DeepCopy_v1_VolumeSource(in interface{}, out interface{}, c *conversion.Clo
if in.ISCSI != nil {
in, out := &in.ISCSI, &out.ISCSI
*out = new(ISCSIVolumeSource)
**out = **in
if err := DeepCopy_v1_ISCSIVolumeSource(*in, *out, c); err != nil {
return err
}
}
if in.Glusterfs != nil {
in, out := &in.Glusterfs, &out.Glusterfs

View File

@ -1168,6 +1168,11 @@ func DeepCopy_api_ISCSIVolumeSource(in interface{}, out interface{}, c *conversi
in := in.(*ISCSIVolumeSource)
out := out.(*ISCSIVolumeSource)
*out = *in
if in.Portals != nil {
in, out := &in.Portals, &out.Portals
*out = make([]string, len(*in))
copy(*out, *in)
}
return nil
}
}
@ -1934,7 +1939,9 @@ func DeepCopy_api_PersistentVolumeSource(in interface{}, out interface{}, c *con
if in.ISCSI != nil {
in, out := &in.ISCSI, &out.ISCSI
*out = new(ISCSIVolumeSource)
**out = **in
if err := DeepCopy_api_ISCSIVolumeSource(*in, *out, c); err != nil {
return err
}
}
if in.FlexVolume != nil {
in, out := &in.FlexVolume, &out.FlexVolume
@ -3182,7 +3189,9 @@ func DeepCopy_api_VolumeSource(in interface{}, out interface{}, c *conversion.Cl
if in.ISCSI != nil {
in, out := &in.ISCSI, &out.ISCSI
*out = new(ISCSIVolumeSource)
**out = **in
if err := DeepCopy_api_ISCSIVolumeSource(*in, *out, c); err != nil {
return err
}
}
if in.Glusterfs != nil {
in, out := &in.Glusterfs, &out.Glusterfs

View File

@ -3017,6 +3017,20 @@ func GetOpenAPIDefinitions(ref openapi.ReferenceCallback) map[string]openapi.Ope
Format: "",
},
},
"portals": {
SchemaProps: spec.SchemaProps{
Description: "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).",
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
Format: "",
},
},
},
},
},
},
Required: []string{"targetPortal", "iqn", "lun"},
},

View File

@ -104,14 +104,18 @@ func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UI
lun := strconv.Itoa(int(iscsi.Lun))
portal := portalMounter(iscsi.TargetPortal)
var bkportal []string
bkportal = append(bkportal, portal)
for _, tp := range iscsi.Portals {
bkportal = append(bkportal, portalMounter(string(tp)))
}
iface := iscsi.ISCSIInterface
return &iscsiDiskMounter{
iscsiDisk: &iscsiDisk{
podUID: podUID,
volName: spec.Name(),
portal: portal,
portals: bkportal,
iqn: iscsi.IQN,
lun: lun,
iface: iface,
@ -162,7 +166,7 @@ func (plugin *iscsiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*v
type iscsiDisk struct {
volName string
podUID types.UID
portal string
portals []string
iqn string
lun string
iface string

View File

@ -98,13 +98,13 @@ func makePDNameInternal(host volume.VolumeHost, portal string, iqn string, lun s
type ISCSIUtil struct{}
func (util *ISCSIUtil) MakeGlobalPDName(iscsi iscsiDisk) string {
return makePDNameInternal(iscsi.plugin.host, iscsi.portal, iscsi.iqn, iscsi.lun)
return makePDNameInternal(iscsi.plugin.host, iscsi.portals[0], iscsi.iqn, iscsi.lun)
}
func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error {
var devicePath string
var devicePaths []string
var iscsiTransport string
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "iface", "-I", b.iface, "-o", "show"})
if err != nil {
glog.Errorf("iscsi: could not read iface %s error: %s", b.iface, string(out))
@ -112,34 +112,50 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error {
}
iscsiTransport = extractTransportname(string(out))
bkpPortal := b.portals
for _, tp := range bkpPortal {
if iscsiTransport == "" {
glog.Errorf("iscsi: could not find transport name in iface %s", b.iface)
return errors.New(fmt.Sprintf("Could not parse iface file for %s", b.iface))
} else if iscsiTransport == "tcp" {
devicePath = strings.Join([]string{"/dev/disk/by-path/ip", b.portal, "iscsi", b.iqn, "lun", b.lun}, "-")
devicePath = strings.Join([]string{"/dev/disk/by-path/ip", tp, "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}, "-")
devicePath = strings.Join([]string{"/dev/disk/by-path/pci", "*", "ip", tp, "iscsi", b.iqn, "lun", b.lun}, "-")
}
exist := waitForPathToExist(devicePath, 1, iscsiTransport)
if exist == false {
// discover iscsi target
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "discovery", "-t", "sendtargets", "-p", b.portal, "-I", b.iface})
out, err := b.plugin.execCommand("iscsiadm", []string{"-m", "discovery", "-t", "sendtargets", "-p", tp, "-I", b.iface})
if err != nil {
glog.Errorf("iscsi: failed to sendtargets to portal %s error: %s", b.portal, string(out))
return err
glog.Errorf("iscsi: failed to sendtargets to portal %s error: %s", tp, string(out))
continue
}
// login to iscsi target
out, err = b.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", b.portal, "-T", b.iqn, "-I", b.iface, "--login"})
out, err = b.plugin.execCommand("iscsiadm", []string{"-m", "node", "-p", tp, "-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
continue
}
exist = waitForPathToExist(devicePath, 10, iscsiTransport)
if !exist {
return errors.New("Could not attach disk: Timeout after 10s")
glog.Errorf("Could not attach disk: Timeout after 10s")
} else {
devicePaths = append(devicePaths, devicePath)
}
} else {
glog.V(4).Infof("iscsi: devicepath (%s) exists", devicePath)
devicePaths = append(devicePaths, devicePath)
}
}
if len(devicePaths) == 0 {
glog.Errorf("iscsi: failed to get any path for iscsi disk")
return errors.New("failed to get any path for iscsi disk")
}
//Make sure we use a valid devicepath to find mpio device.
devicePath = devicePaths[0]
// mount it
globalPDPath := b.manager.MakeGlobalPDName(*b.iscsiDisk)
notMnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath)
@ -153,9 +169,17 @@ func (util *ISCSIUtil) AttachDisk(b iscsiDiskMounter) error {
return err
}
for _, path := range devicePaths {
// There shouldnt be any empty device paths. However adding this check
// for safer side to avoid the possibility of an empty entry.
if path == "" {
continue
}
// check if the dev is using mpio and if so mount it via the dm-XX device
if mappedDevicePath := b.deviceUtil.FindMultipathDeviceForDevice(devicePath); mappedDevicePath != "" {
if mappedDevicePath := b.deviceUtil.FindMultipathDeviceForDevice(path); mappedDevicePath != "" {
devicePath = mappedDevicePath
break
}
}
err = b.mounter.FormatAndMount(devicePath, globalPDPath, b.fsType, nil)
if err != nil {