mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #22575 from MikaelCluseau/wip-issue-20466
Automatic merge from submit-queue Add subPath to mount a child dir or file of a volumeMount Allow users to specify a subPath in Container.volumeMounts so they can use a single volume for many mounts instead of creating many volumes. For instance, a user can now use a single PersistentVolume to store the Mysql database and the document root of an Apache server of a LAMP stack pod by mapping them to different subPaths in this single volume. Also solves https://github.com/kubernetes/kubernetes/issues/20466.
This commit is contained in:
commit
f2f3b49f58
@ -2031,6 +2031,10 @@
|
|||||||
"mountPath": {
|
"mountPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path within the container at which the volume should be mounted. Must not contain ':'."
|
"description": "Path within the container at which the volume should be mounted. Must not contain ':'."
|
||||||
|
},
|
||||||
|
"subPath": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2036,6 +2036,10 @@
|
|||||||
"mountPath": {
|
"mountPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path within the container at which the volume should be mounted. Must not contain ':'."
|
"description": "Path within the container at which the volume should be mounted. Must not contain ':'."
|
||||||
|
},
|
||||||
|
"subPath": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7343,6 +7343,10 @@
|
|||||||
"mountPath": {
|
"mountPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path within the container at which the volume should be mounted. Must not contain ':'."
|
"description": "Path within the container at which the volume should be mounted. Must not contain ':'."
|
||||||
|
},
|
||||||
|
"subPath": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -17330,6 +17330,10 @@
|
|||||||
"mountPath": {
|
"mountPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path within the container at which the volume should be mounted. Must not contain ':'."
|
"description": "Path within the container at which the volume should be mounted. Must not contain ':'."
|
||||||
|
},
|
||||||
|
"subPath": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -556,6 +556,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="tableblock halign-left valign-top"><p class="tableblock">subPath</p></td>
|
||||||
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Path within the volume from which the container’s volume should be mounted. Defaults to "" (volume’s root).</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>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -3972,7 +3979,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
|||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div id="footer-text">
|
<div id="footer-text">
|
||||||
Last updated 2016-05-02 18:47:09 UTC
|
Last updated 2016-05-06 04:28:34 UTC
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
@ -770,6 +770,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="tableblock halign-left valign-top"><p class="tableblock">subPath</p></td>
|
||||||
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Path within the volume from which the container’s volume should be mounted. Defaults to "" (volume’s root).</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>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -5962,7 +5969,7 @@ Both these may change in the future. Incoming requests are matched against the h
|
|||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div id="footer-text">
|
<div id="footer-text">
|
||||||
Last updated 2016-05-02 18:47:04 UTC
|
Last updated 2016-05-06 04:28:25 UTC
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
@ -803,6 +803,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="tableblock halign-left valign-top"><p class="tableblock">subPath</p></td>
|
||||||
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Path within the volume from which the container’s volume should be mounted. Defaults to "" (volume’s root).</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>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -7839,7 +7846,7 @@ The resulting set of endpoints can be viewed as:<br>
|
|||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div id="footer-text">
|
<div id="footer-text">
|
||||||
Last updated 2016-05-02 18:46:58 UTC
|
Last updated 2016-05-06 04:28:14 UTC
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
@ -92,3 +92,4 @@ test/e2e/host_path.go: fmt.Sprintf("--retry_time=%d", retryDuration),
|
|||||||
test/images/mount-tester/mt.go: flag.BoolVar(&breakOnExpectedContent, "break_on_expected_content", true, "Break out of loop on expected content, (use with --file_content_in_loop flag only)")
|
test/images/mount-tester/mt.go: flag.BoolVar(&breakOnExpectedContent, "break_on_expected_content", true, "Break out of loop on expected content, (use with --file_content_in_loop flag only)")
|
||||||
test/images/mount-tester/mt.go: flag.IntVar(&retryDuration, "retry_time", 180, "Retry time during the loop")
|
test/images/mount-tester/mt.go: flag.IntVar(&retryDuration, "retry_time", 180, "Retry time during the loop")
|
||||||
test/images/mount-tester/mt.go: flag.StringVar(&readFileContentInLoopPath, "file_content_in_loop", "", "Path to read the file content in loop from")
|
test/images/mount-tester/mt.go: flag.StringVar(&readFileContentInLoopPath, "file_content_in_loop", "", "Path to read the file content in loop from")
|
||||||
|
test/e2e/host_path.go: fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
|
||||||
|
@ -2955,6 +2955,7 @@ func DeepCopy_api_VolumeMount(in VolumeMount, out *VolumeMount, c *conversion.Cl
|
|||||||
out.Name = in.Name
|
out.Name = in.Name
|
||||||
out.ReadOnly = in.ReadOnly
|
out.ReadOnly = in.ReadOnly
|
||||||
out.MountPath = in.MountPath
|
out.MountPath = in.MountPath
|
||||||
|
out.SubPath = in.SubPath
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14340,13 +14340,14 @@ func (x *VolumeMount) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||||||
} else {
|
} else {
|
||||||
yysep2 := !z.EncBinary()
|
yysep2 := !z.EncBinary()
|
||||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||||
var yyq2 [3]bool
|
var yyq2 [4]bool
|
||||||
_, _, _ = yysep2, yyq2, yy2arr2
|
_, _, _ = yysep2, yyq2, yy2arr2
|
||||||
const yyr2 bool = false
|
const yyr2 bool = false
|
||||||
yyq2[1] = x.ReadOnly != false
|
yyq2[1] = x.ReadOnly != false
|
||||||
|
yyq2[3] = x.SubPath != ""
|
||||||
var yynn2 int
|
var yynn2 int
|
||||||
if yyr2 || yy2arr2 {
|
if yyr2 || yy2arr2 {
|
||||||
r.EncodeArrayStart(3)
|
r.EncodeArrayStart(4)
|
||||||
} else {
|
} else {
|
||||||
yynn2 = 2
|
yynn2 = 2
|
||||||
for _, b := range yyq2 {
|
for _, b := range yyq2 {
|
||||||
@ -14420,6 +14421,31 @@ func (x *VolumeMount) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||||||
r.EncodeString(codecSelferC_UTF81234, string(x.MountPath))
|
r.EncodeString(codecSelferC_UTF81234, string(x.MountPath))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if yyr2 || yy2arr2 {
|
||||||
|
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||||
|
if yyq2[3] {
|
||||||
|
yym13 := z.EncBinary()
|
||||||
|
_ = yym13
|
||||||
|
if false {
|
||||||
|
} else {
|
||||||
|
r.EncodeString(codecSelferC_UTF81234, string(x.SubPath))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r.EncodeString(codecSelferC_UTF81234, "")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if yyq2[3] {
|
||||||
|
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||||
|
r.EncodeString(codecSelferC_UTF81234, string("subPath"))
|
||||||
|
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||||
|
yym14 := z.EncBinary()
|
||||||
|
_ = yym14
|
||||||
|
if false {
|
||||||
|
} else {
|
||||||
|
r.EncodeString(codecSelferC_UTF81234, string(x.SubPath))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if yyr2 || yy2arr2 {
|
if yyr2 || yy2arr2 {
|
||||||
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
} else {
|
} else {
|
||||||
@ -14499,6 +14525,12 @@ func (x *VolumeMount) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
|||||||
} else {
|
} else {
|
||||||
x.MountPath = string(r.DecodeString())
|
x.MountPath = string(r.DecodeString())
|
||||||
}
|
}
|
||||||
|
case "subPath":
|
||||||
|
if r.TryDecodeAsNil() {
|
||||||
|
x.SubPath = ""
|
||||||
|
} else {
|
||||||
|
x.SubPath = string(r.DecodeString())
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
z.DecStructFieldNotFound(-1, yys3)
|
z.DecStructFieldNotFound(-1, yys3)
|
||||||
} // end switch yys3
|
} // end switch yys3
|
||||||
@ -14510,16 +14542,16 @@ func (x *VolumeMount) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||||||
var h codecSelfer1234
|
var h codecSelfer1234
|
||||||
z, r := codec1978.GenHelperDecoder(d)
|
z, r := codec1978.GenHelperDecoder(d)
|
||||||
_, _, _ = h, z, r
|
_, _, _ = h, z, r
|
||||||
var yyj7 int
|
var yyj8 int
|
||||||
var yyb7 bool
|
var yyb8 bool
|
||||||
var yyhl7 bool = l >= 0
|
var yyhl8 bool = l >= 0
|
||||||
yyj7++
|
yyj8++
|
||||||
if yyhl7 {
|
if yyhl8 {
|
||||||
yyb7 = yyj7 > l
|
yyb8 = yyj8 > l
|
||||||
} else {
|
} else {
|
||||||
yyb7 = r.CheckBreak()
|
yyb8 = r.CheckBreak()
|
||||||
}
|
}
|
||||||
if yyb7 {
|
if yyb8 {
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -14529,13 +14561,13 @@ func (x *VolumeMount) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||||||
} else {
|
} else {
|
||||||
x.Name = string(r.DecodeString())
|
x.Name = string(r.DecodeString())
|
||||||
}
|
}
|
||||||
yyj7++
|
yyj8++
|
||||||
if yyhl7 {
|
if yyhl8 {
|
||||||
yyb7 = yyj7 > l
|
yyb8 = yyj8 > l
|
||||||
} else {
|
} else {
|
||||||
yyb7 = r.CheckBreak()
|
yyb8 = r.CheckBreak()
|
||||||
}
|
}
|
||||||
if yyb7 {
|
if yyb8 {
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -14545,13 +14577,13 @@ func (x *VolumeMount) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||||||
} else {
|
} else {
|
||||||
x.ReadOnly = bool(r.DecodeBool())
|
x.ReadOnly = bool(r.DecodeBool())
|
||||||
}
|
}
|
||||||
yyj7++
|
yyj8++
|
||||||
if yyhl7 {
|
if yyhl8 {
|
||||||
yyb7 = yyj7 > l
|
yyb8 = yyj8 > l
|
||||||
} else {
|
} else {
|
||||||
yyb7 = r.CheckBreak()
|
yyb8 = r.CheckBreak()
|
||||||
}
|
}
|
||||||
if yyb7 {
|
if yyb8 {
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -14561,18 +14593,34 @@ func (x *VolumeMount) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||||||
} else {
|
} else {
|
||||||
x.MountPath = string(r.DecodeString())
|
x.MountPath = string(r.DecodeString())
|
||||||
}
|
}
|
||||||
for {
|
yyj8++
|
||||||
yyj7++
|
if yyhl8 {
|
||||||
if yyhl7 {
|
yyb8 = yyj8 > l
|
||||||
yyb7 = yyj7 > l
|
|
||||||
} else {
|
} else {
|
||||||
yyb7 = r.CheckBreak()
|
yyb8 = r.CheckBreak()
|
||||||
}
|
}
|
||||||
if yyb7 {
|
if yyb8 {
|
||||||
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||||
|
if r.TryDecodeAsNil() {
|
||||||
|
x.SubPath = ""
|
||||||
|
} else {
|
||||||
|
x.SubPath = string(r.DecodeString())
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
yyj8++
|
||||||
|
if yyhl8 {
|
||||||
|
yyb8 = yyj8 > l
|
||||||
|
} else {
|
||||||
|
yyb8 = r.CheckBreak()
|
||||||
|
}
|
||||||
|
if yyb8 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||||
z.DecStructFieldNotFound(yyj7-1, "")
|
z.DecStructFieldNotFound(yyj8-1, "")
|
||||||
}
|
}
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
}
|
}
|
||||||
@ -52291,7 +52339,7 @@ func (x codecSelfer1234) decSliceVolumeMount(v *[]VolumeMount, d *codec1978.Deco
|
|||||||
|
|
||||||
yyrg1 := len(yyv1) > 0
|
yyrg1 := len(yyv1) > 0
|
||||||
yyv21 := yyv1
|
yyv21 := yyv1
|
||||||
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 40)
|
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 56)
|
||||||
if yyrt1 {
|
if yyrt1 {
|
||||||
if yyrl1 <= cap(yyv1) {
|
if yyrl1 <= cap(yyv1) {
|
||||||
yyv1 = yyv1[:yyrl1]
|
yyv1 = yyv1[:yyrl1]
|
||||||
|
@ -758,6 +758,9 @@ type VolumeMount struct {
|
|||||||
ReadOnly bool `json:"readOnly,omitempty"`
|
ReadOnly bool `json:"readOnly,omitempty"`
|
||||||
// Required. Must not contain ':'.
|
// Required. Must not contain ':'.
|
||||||
MountPath string `json:"mountPath"`
|
MountPath string `json:"mountPath"`
|
||||||
|
// Path within the volume from which the container's volume should be mounted.
|
||||||
|
// Defaults to "" (volume's root).
|
||||||
|
SubPath string `json:"subPath,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnvVar represents an environment variable present in a Container.
|
// EnvVar represents an environment variable present in a Container.
|
||||||
|
@ -6556,6 +6556,7 @@ func autoConvert_v1_VolumeMount_To_api_VolumeMount(in *VolumeMount, out *api.Vol
|
|||||||
out.Name = in.Name
|
out.Name = in.Name
|
||||||
out.ReadOnly = in.ReadOnly
|
out.ReadOnly = in.ReadOnly
|
||||||
out.MountPath = in.MountPath
|
out.MountPath = in.MountPath
|
||||||
|
out.SubPath = in.SubPath
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6567,6 +6568,7 @@ func autoConvert_api_VolumeMount_To_v1_VolumeMount(in *api.VolumeMount, out *Vol
|
|||||||
out.Name = in.Name
|
out.Name = in.Name
|
||||||
out.ReadOnly = in.ReadOnly
|
out.ReadOnly = in.ReadOnly
|
||||||
out.MountPath = in.MountPath
|
out.MountPath = in.MountPath
|
||||||
|
out.SubPath = in.SubPath
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2916,6 +2916,7 @@ func DeepCopy_v1_VolumeMount(in VolumeMount, out *VolumeMount, c *conversion.Clo
|
|||||||
out.Name = in.Name
|
out.Name = in.Name
|
||||||
out.ReadOnly = in.ReadOnly
|
out.ReadOnly = in.ReadOnly
|
||||||
out.MountPath = in.MountPath
|
out.MountPath = in.MountPath
|
||||||
|
out.SubPath = in.SubPath
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7164,6 +7164,10 @@ func (m *VolumeMount) MarshalTo(data []byte) (int, error) {
|
|||||||
i++
|
i++
|
||||||
i = encodeVarintGenerated(data, i, uint64(len(m.MountPath)))
|
i = encodeVarintGenerated(data, i, uint64(len(m.MountPath)))
|
||||||
i += copy(data[i:], m.MountPath)
|
i += copy(data[i:], m.MountPath)
|
||||||
|
data[i] = 0x22
|
||||||
|
i++
|
||||||
|
i = encodeVarintGenerated(data, i, uint64(len(m.SubPath)))
|
||||||
|
i += copy(data[i:], m.SubPath)
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9726,6 +9730,8 @@ func (m *VolumeMount) Size() (n int) {
|
|||||||
n += 2
|
n += 2
|
||||||
l = len(m.MountPath)
|
l = len(m.MountPath)
|
||||||
n += 1 + l + sovGenerated(uint64(l))
|
n += 1 + l + sovGenerated(uint64(l))
|
||||||
|
l = len(m.SubPath)
|
||||||
|
n += 1 + l + sovGenerated(uint64(l))
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32282,6 +32288,35 @@ func (m *VolumeMount) Unmarshal(data []byte) error {
|
|||||||
}
|
}
|
||||||
m.MountPath = string(data[iNdEx:postIndex])
|
m.MountPath = string(data[iNdEx:postIndex])
|
||||||
iNdEx = postIndex
|
iNdEx = postIndex
|
||||||
|
case 4:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field SubPath", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowGenerated
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
stringLen |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intStringLen := int(stringLen)
|
||||||
|
if intStringLen < 0 {
|
||||||
|
return ErrInvalidLengthGenerated
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.SubPath = string(data[iNdEx:postIndex])
|
||||||
|
iNdEx = postIndex
|
||||||
default:
|
default:
|
||||||
iNdEx = preIndex
|
iNdEx = preIndex
|
||||||
skippy, err := skipGenerated(data[iNdEx:])
|
skippy, err := skipGenerated(data[iNdEx:])
|
||||||
|
@ -2705,6 +2705,10 @@ message VolumeMount {
|
|||||||
// Path within the container at which the volume should be mounted. Must
|
// Path within the container at which the volume should be mounted. Must
|
||||||
// not contain ':'.
|
// not contain ':'.
|
||||||
optional string mountPath = 3;
|
optional string mountPath = 3;
|
||||||
|
|
||||||
|
// Path within the volume from which the container's volume should be mounted.
|
||||||
|
// Defaults to "" (volume's root).
|
||||||
|
optional string subPath = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents the source of a volume to mount.
|
// Represents the source of a volume to mount.
|
||||||
|
@ -13943,13 +13943,14 @@ func (x *VolumeMount) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||||||
} else {
|
} else {
|
||||||
yysep2 := !z.EncBinary()
|
yysep2 := !z.EncBinary()
|
||||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||||
var yyq2 [3]bool
|
var yyq2 [4]bool
|
||||||
_, _, _ = yysep2, yyq2, yy2arr2
|
_, _, _ = yysep2, yyq2, yy2arr2
|
||||||
const yyr2 bool = false
|
const yyr2 bool = false
|
||||||
yyq2[1] = x.ReadOnly != false
|
yyq2[1] = x.ReadOnly != false
|
||||||
|
yyq2[3] = x.SubPath != ""
|
||||||
var yynn2 int
|
var yynn2 int
|
||||||
if yyr2 || yy2arr2 {
|
if yyr2 || yy2arr2 {
|
||||||
r.EncodeArrayStart(3)
|
r.EncodeArrayStart(4)
|
||||||
} else {
|
} else {
|
||||||
yynn2 = 2
|
yynn2 = 2
|
||||||
for _, b := range yyq2 {
|
for _, b := range yyq2 {
|
||||||
@ -14023,6 +14024,31 @@ func (x *VolumeMount) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||||||
r.EncodeString(codecSelferC_UTF81234, string(x.MountPath))
|
r.EncodeString(codecSelferC_UTF81234, string(x.MountPath))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if yyr2 || yy2arr2 {
|
||||||
|
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||||
|
if yyq2[3] {
|
||||||
|
yym13 := z.EncBinary()
|
||||||
|
_ = yym13
|
||||||
|
if false {
|
||||||
|
} else {
|
||||||
|
r.EncodeString(codecSelferC_UTF81234, string(x.SubPath))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r.EncodeString(codecSelferC_UTF81234, "")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if yyq2[3] {
|
||||||
|
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||||
|
r.EncodeString(codecSelferC_UTF81234, string("subPath"))
|
||||||
|
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||||
|
yym14 := z.EncBinary()
|
||||||
|
_ = yym14
|
||||||
|
if false {
|
||||||
|
} else {
|
||||||
|
r.EncodeString(codecSelferC_UTF81234, string(x.SubPath))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if yyr2 || yy2arr2 {
|
if yyr2 || yy2arr2 {
|
||||||
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
} else {
|
} else {
|
||||||
@ -14102,6 +14128,12 @@ func (x *VolumeMount) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
|||||||
} else {
|
} else {
|
||||||
x.MountPath = string(r.DecodeString())
|
x.MountPath = string(r.DecodeString())
|
||||||
}
|
}
|
||||||
|
case "subPath":
|
||||||
|
if r.TryDecodeAsNil() {
|
||||||
|
x.SubPath = ""
|
||||||
|
} else {
|
||||||
|
x.SubPath = string(r.DecodeString())
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
z.DecStructFieldNotFound(-1, yys3)
|
z.DecStructFieldNotFound(-1, yys3)
|
||||||
} // end switch yys3
|
} // end switch yys3
|
||||||
@ -14113,16 +14145,16 @@ func (x *VolumeMount) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||||||
var h codecSelfer1234
|
var h codecSelfer1234
|
||||||
z, r := codec1978.GenHelperDecoder(d)
|
z, r := codec1978.GenHelperDecoder(d)
|
||||||
_, _, _ = h, z, r
|
_, _, _ = h, z, r
|
||||||
var yyj7 int
|
var yyj8 int
|
||||||
var yyb7 bool
|
var yyb8 bool
|
||||||
var yyhl7 bool = l >= 0
|
var yyhl8 bool = l >= 0
|
||||||
yyj7++
|
yyj8++
|
||||||
if yyhl7 {
|
if yyhl8 {
|
||||||
yyb7 = yyj7 > l
|
yyb8 = yyj8 > l
|
||||||
} else {
|
} else {
|
||||||
yyb7 = r.CheckBreak()
|
yyb8 = r.CheckBreak()
|
||||||
}
|
}
|
||||||
if yyb7 {
|
if yyb8 {
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -14132,13 +14164,13 @@ func (x *VolumeMount) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||||||
} else {
|
} else {
|
||||||
x.Name = string(r.DecodeString())
|
x.Name = string(r.DecodeString())
|
||||||
}
|
}
|
||||||
yyj7++
|
yyj8++
|
||||||
if yyhl7 {
|
if yyhl8 {
|
||||||
yyb7 = yyj7 > l
|
yyb8 = yyj8 > l
|
||||||
} else {
|
} else {
|
||||||
yyb7 = r.CheckBreak()
|
yyb8 = r.CheckBreak()
|
||||||
}
|
}
|
||||||
if yyb7 {
|
if yyb8 {
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -14148,13 +14180,13 @@ func (x *VolumeMount) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||||||
} else {
|
} else {
|
||||||
x.ReadOnly = bool(r.DecodeBool())
|
x.ReadOnly = bool(r.DecodeBool())
|
||||||
}
|
}
|
||||||
yyj7++
|
yyj8++
|
||||||
if yyhl7 {
|
if yyhl8 {
|
||||||
yyb7 = yyj7 > l
|
yyb8 = yyj8 > l
|
||||||
} else {
|
} else {
|
||||||
yyb7 = r.CheckBreak()
|
yyb8 = r.CheckBreak()
|
||||||
}
|
}
|
||||||
if yyb7 {
|
if yyb8 {
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -14164,18 +14196,34 @@ func (x *VolumeMount) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||||||
} else {
|
} else {
|
||||||
x.MountPath = string(r.DecodeString())
|
x.MountPath = string(r.DecodeString())
|
||||||
}
|
}
|
||||||
for {
|
yyj8++
|
||||||
yyj7++
|
if yyhl8 {
|
||||||
if yyhl7 {
|
yyb8 = yyj8 > l
|
||||||
yyb7 = yyj7 > l
|
|
||||||
} else {
|
} else {
|
||||||
yyb7 = r.CheckBreak()
|
yyb8 = r.CheckBreak()
|
||||||
}
|
}
|
||||||
if yyb7 {
|
if yyb8 {
|
||||||
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||||
|
if r.TryDecodeAsNil() {
|
||||||
|
x.SubPath = ""
|
||||||
|
} else {
|
||||||
|
x.SubPath = string(r.DecodeString())
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
yyj8++
|
||||||
|
if yyhl8 {
|
||||||
|
yyb8 = yyj8 > l
|
||||||
|
} else {
|
||||||
|
yyb8 = r.CheckBreak()
|
||||||
|
}
|
||||||
|
if yyb8 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||||
z.DecStructFieldNotFound(yyj7-1, "")
|
z.DecStructFieldNotFound(yyj8-1, "")
|
||||||
}
|
}
|
||||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||||
}
|
}
|
||||||
@ -52344,7 +52392,7 @@ func (x codecSelfer1234) decSliceVolumeMount(v *[]VolumeMount, d *codec1978.Deco
|
|||||||
|
|
||||||
yyrg1 := len(yyv1) > 0
|
yyrg1 := len(yyv1) > 0
|
||||||
yyv21 := yyv1
|
yyv21 := yyv1
|
||||||
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 40)
|
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 56)
|
||||||
if yyrt1 {
|
if yyrt1 {
|
||||||
if yyrl1 <= cap(yyv1) {
|
if yyrl1 <= cap(yyv1) {
|
||||||
yyv1 = yyv1[:yyrl1]
|
yyv1 = yyv1[:yyrl1]
|
||||||
|
@ -883,6 +883,9 @@ type VolumeMount struct {
|
|||||||
// Path within the container at which the volume should be mounted. Must
|
// Path within the container at which the volume should be mounted. Must
|
||||||
// not contain ':'.
|
// not contain ':'.
|
||||||
MountPath string `json:"mountPath" protobuf:"bytes,3,opt,name=mountPath"`
|
MountPath string `json:"mountPath" protobuf:"bytes,3,opt,name=mountPath"`
|
||||||
|
// Path within the volume from which the container's volume should be mounted.
|
||||||
|
// Defaults to "" (volume's root).
|
||||||
|
SubPath string `json:"subPath,omitempty" protobuf:"bytes,4,opt,name=subPath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnvVar represents an environment variable present in a Container.
|
// EnvVar represents an environment variable present in a Container.
|
||||||
|
@ -1628,6 +1628,7 @@ var map_VolumeMount = map[string]string{
|
|||||||
"name": "This must match the Name of a Volume.",
|
"name": "This must match the Name of a Volume.",
|
||||||
"readOnly": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.",
|
"readOnly": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.",
|
||||||
"mountPath": "Path within the container at which the volume should be mounted. Must not contain ':'.",
|
"mountPath": "Path within the container at which the volume should be mounted. Must not contain ':'.",
|
||||||
|
"subPath": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root).",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (VolumeMount) SwaggerDoc() map[string]string {
|
func (VolumeMount) SwaggerDoc() map[string]string {
|
||||||
|
@ -727,6 +727,28 @@ func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSou
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This validate will make sure targetPath:
|
||||||
|
// 1. is not abs path
|
||||||
|
// 2. does not start with '../'
|
||||||
|
// 3. does not contain '/../'
|
||||||
|
// 4. does not end with '/..'
|
||||||
|
func validateSubPath(targetPath string, fldPath *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
if path.IsAbs(targetPath) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must be a relative path"))
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(targetPath, "../") {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not start with '../'"))
|
||||||
|
}
|
||||||
|
if strings.Contains(targetPath, "/../") {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not contain '/../'"))
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(targetPath, "/..") {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not end with '/..'"))
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
// This validate will make sure targetPath:
|
// This validate will make sure targetPath:
|
||||||
// 1. is not abs path
|
// 1. is not abs path
|
||||||
// 2. does not contain '..'
|
// 2. does not contain '..'
|
||||||
@ -1149,6 +1171,9 @@ func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath
|
|||||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must be unique"))
|
allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must be unique"))
|
||||||
}
|
}
|
||||||
mountpoints.Insert(mnt.MountPath)
|
mountpoints.Insert(mnt.MountPath)
|
||||||
|
if len(mnt.SubPath) > 0 {
|
||||||
|
allErrs = append(allErrs, validateSubPath(mnt.SubPath, fldPath.Child("subPath"))...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
@ -1213,6 +1213,10 @@ func TestValidateVolumeMounts(t *testing.T) {
|
|||||||
{Name: "abc", MountPath: "/foo"},
|
{Name: "abc", MountPath: "/foo"},
|
||||||
{Name: "123", MountPath: "/bar"},
|
{Name: "123", MountPath: "/bar"},
|
||||||
{Name: "abc-123", MountPath: "/baz"},
|
{Name: "abc-123", MountPath: "/baz"},
|
||||||
|
{Name: "abc-123", MountPath: "/baa", SubPath: ""},
|
||||||
|
{Name: "abc-123", MountPath: "/bab", SubPath: "baz"},
|
||||||
|
{Name: "abc-123", MountPath: "/bac", SubPath: ".baz"},
|
||||||
|
{Name: "abc-123", MountPath: "/bad", SubPath: "..baz"},
|
||||||
}
|
}
|
||||||
if errs := validateVolumeMounts(successCase, volumes, field.NewPath("field")); len(errs) != 0 {
|
if errs := validateVolumeMounts(successCase, volumes, field.NewPath("field")); len(errs) != 0 {
|
||||||
t.Errorf("expected success: %v", errs)
|
t.Errorf("expected success: %v", errs)
|
||||||
@ -1224,6 +1228,10 @@ func TestValidateVolumeMounts(t *testing.T) {
|
|||||||
"empty mountpath": {{Name: "abc", MountPath: ""}},
|
"empty mountpath": {{Name: "abc", MountPath: ""}},
|
||||||
"colon mountpath": {{Name: "abc", MountPath: "foo:bar"}},
|
"colon mountpath": {{Name: "abc", MountPath: "foo:bar"}},
|
||||||
"mountpath collision": {{Name: "foo", MountPath: "/path/a"}, {Name: "bar", MountPath: "/path/a"}},
|
"mountpath collision": {{Name: "foo", MountPath: "/path/a"}, {Name: "bar", MountPath: "/path/a"}},
|
||||||
|
"absolute subpath": {{Name: "abc", MountPath: "/bar", SubPath: "/baz"}},
|
||||||
|
"subpath in ..": {{Name: "abc", MountPath: "/bar", SubPath: "../baz"}},
|
||||||
|
"subpath contains ..": {{Name: "abc", MountPath: "/bar", SubPath: "baz/../bat"}},
|
||||||
|
"subpath ends in ..": {{Name: "abc", MountPath: "/bar", SubPath: "./.."}},
|
||||||
}
|
}
|
||||||
for k, v := range errorCases {
|
for k, v := range errorCases {
|
||||||
if errs := validateVolumeMounts(v, volumes, field.NewPath("field")); len(errs) == 0 {
|
if errs := validateVolumeMounts(v, volumes, field.NewPath("field")); len(errs) == 0 {
|
||||||
|
@ -1187,10 +1187,14 @@ func makeMounts(pod *api.Pod, podDir string, container *api.Container, hostName,
|
|||||||
vol.SELinuxLabeled = true
|
vol.SELinuxLabeled = true
|
||||||
relabelVolume = true
|
relabelVolume = true
|
||||||
}
|
}
|
||||||
|
hostPath := vol.Mounter.GetPath()
|
||||||
|
if mount.SubPath != "" {
|
||||||
|
hostPath = filepath.Join(hostPath, mount.SubPath)
|
||||||
|
}
|
||||||
mounts = append(mounts, kubecontainer.Mount{
|
mounts = append(mounts, kubecontainer.Mount{
|
||||||
Name: mount.Name,
|
Name: mount.Name,
|
||||||
ContainerPath: mount.MountPath,
|
ContainerPath: mount.MountPath,
|
||||||
HostPath: vol.Mounter.GetPath(),
|
HostPath: hostPath,
|
||||||
ReadOnly: mount.ReadOnly,
|
ReadOnly: mount.ReadOnly,
|
||||||
SELinuxRelabel: relabelVolume,
|
SELinuxRelabel: relabelVolume,
|
||||||
})
|
})
|
||||||
|
@ -88,6 +88,37 @@ var _ = framework.KubeDescribe("hostPath", func() {
|
|||||||
}, namespace.Name,
|
}, namespace.Name,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("should support subPath [Conformance]", func() {
|
||||||
|
volumePath := "/test-volume"
|
||||||
|
subPath := "sub-path"
|
||||||
|
fileName := "test-file"
|
||||||
|
retryDuration := 180
|
||||||
|
|
||||||
|
filePathInWriter := path.Join(volumePath, fileName)
|
||||||
|
filePathInReader := path.Join(volumePath, subPath, fileName)
|
||||||
|
|
||||||
|
source := &api.HostPathVolumeSource{
|
||||||
|
Path: "/tmp",
|
||||||
|
}
|
||||||
|
pod := testPodWithHostVol(volumePath, source)
|
||||||
|
// Write the file in the subPath from container 0
|
||||||
|
container := &pod.Spec.Containers[0]
|
||||||
|
container.VolumeMounts[0].SubPath = subPath
|
||||||
|
container.Args = []string{
|
||||||
|
fmt.Sprintf("--new_file_0644=%v", filePathInWriter),
|
||||||
|
fmt.Sprintf("--file_mode=%v", filePathInWriter),
|
||||||
|
}
|
||||||
|
// Read it from outside the subPath from container 1
|
||||||
|
pod.Spec.Containers[1].Args = []string{
|
||||||
|
fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
|
||||||
|
fmt.Sprintf("--retry_time=%d", retryDuration),
|
||||||
|
}
|
||||||
|
|
||||||
|
framework.TestContainerOutput("hostPath subPath", c, pod, 1, []string{
|
||||||
|
"content of file \"" + filePathInReader + "\": mount-tester new file",
|
||||||
|
}, namespace.Name)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
//These constants are borrowed from the other test.
|
//These constants are borrowed from the other test.
|
||||||
|
Loading…
Reference in New Issue
Block a user