Merge pull request #44785 from jingxu97/April/apistorage

Automatic merge from submit-queue

Add Local Storage Capacity Isolation API

This PR adds the new APIs to support storage capacity isolation as
described in the proposal [https://github.com/kubernetes/community/pull/306](url)

1. Add SizeLimit for emptyDir volume
2. Add scratch and overlay storage type used by container level or
node level


**Release note**:

```release-note
Alpha feature: Local volume Storage Capacity Isolation allows users to set storage limit to isolate EmptyDir volumes, container storage overlay, and also supports allocatable storage for shared root file system. 
```
pull/6/head
Kubernetes Submit Queue 2017-06-01 09:12:19 -07:00 committed by GitHub
commit 14a1cdd208
37 changed files with 3056 additions and 2576 deletions

View File

@ -46705,6 +46705,10 @@
"medium": {
"description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir",
"type": "string"
},
"sizeLimit": {
"description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir",
"$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity"
}
}
},

View File

@ -3968,6 +3968,10 @@
"medium": {
"type": "string",
"description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir"
},
"sizeLimit": {
"type": "string",
"description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir"
}
}
},

View File

@ -1715,6 +1715,10 @@
"medium": {
"type": "string",
"description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir"
},
"sizeLimit": {
"type": "string",
"description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir"
}
}
},

View File

@ -2796,6 +2796,10 @@
"medium": {
"type": "string",
"description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir"
},
"sizeLimit": {
"type": "string",
"description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir"
}
}
},

View File

@ -7435,6 +7435,10 @@
"medium": {
"type": "string",
"description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir"
},
"sizeLimit": {
"type": "string",
"description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir"
}
}
},

View File

@ -1580,6 +1580,10 @@
"medium": {
"type": "string",
"description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir"
},
"sizeLimit": {
"type": "string",
"description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir"
}
}
},

View File

@ -19799,6 +19799,10 @@
"medium": {
"type": "string",
"description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir"
},
"sizeLimit": {
"type": "string",
"description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir"
}
}
},

View File

@ -1998,6 +1998,13 @@ When an object is created, the system will populate this list with the current s
<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">sizeLimit</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: <a href="http://kubernetes.io/docs/user-guide/volumes#emptydir">http://kubernetes.io/docs/user-guide/volumes#emptydir</a></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>
</table>
@ -6600,7 +6607,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-05-25 16:54:16 UTC
Last updated 2017-05-31 19:35:31 UTC
</div>
</div>
</body>

View File

@ -1663,6 +1663,13 @@ When an object is created, the system will populate this list with the current s
<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">sizeLimit</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: <a href="http://kubernetes.io/docs/user-guide/volumes#emptydir">http://kubernetes.io/docs/user-guide/volumes#emptydir</a></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>
</table>
@ -5705,7 +5712,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-05-22 06:33:27 UTC
Last updated 2017-05-31 19:35:57 UTC
</div>
</div>
</body>

View File

@ -1663,6 +1663,13 @@ When an object is created, the system will populate this list with the current s
<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">sizeLimit</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: <a href="http://kubernetes.io/docs/user-guide/volumes#emptydir">http://kubernetes.io/docs/user-guide/volumes#emptydir</a></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>
</table>
@ -5801,7 +5808,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-05-22 06:33:33 UTC
Last updated 2017-05-31 19:36:01 UTC
</div>
</div>
</body>

View File

@ -2605,6 +2605,13 @@ When an object is created, the system will populate this list with the current s
<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">sizeLimit</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: <a href="http://kubernetes.io/docs/user-guide/volumes#emptydir">http://kubernetes.io/docs/user-guide/volumes#emptydir</a></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>
</table>
@ -8127,7 +8134,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-05-29 17:05:24 UTC
Last updated 2017-05-31 19:36:09 UTC
</div>
</div>
</body>

View File

@ -2218,6 +2218,13 @@ When an object is created, the system will populate this list with the current s
<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">sizeLimit</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: <a href="http://kubernetes.io/docs/user-guide/volumes#emptydir">http://kubernetes.io/docs/user-guide/volumes#emptydir</a></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>
</table>
@ -3943,7 +3950,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-05-22 06:34:02 UTC
Last updated 2017-05-31 19:36:28 UTC
</div>
</div>
</body>

View File

@ -2744,6 +2744,13 @@ When an object is created, the system will populate this list with the current s
<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">sizeLimit</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: <a href="http://kubernetes.io/docs/user-guide/volumes#emptydir">http://kubernetes.io/docs/user-guide/volumes#emptydir</a></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>
</table>
@ -10098,7 +10105,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-05-22 06:32:47 UTC
Last updated 2017-05-31 19:35:23 UTC
</div>
</div>
</body>

View File

@ -10970,6 +10970,10 @@
"medium": {
"description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir",
"type": "string"
},
"sizeLimit": {
"description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir",
"$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity"
}
}
},

View File

@ -5179,6 +5179,10 @@
"medium": {
"type": "string",
"description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir"
},
"sizeLimit": {
"type": "string",
"description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir"
}
}
},

View File

@ -2436,6 +2436,13 @@ When an object is created, the system will populate this list with the current s
<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">sizeLimit</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: <a href="http://kubernetes.io/docs/user-guide/volumes#emptydir">http://kubernetes.io/docs/user-guide/volumes#emptydir</a></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>
</table>
@ -7197,7 +7204,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-05-25 09:37:16 UTC
Last updated 2017-05-31 19:38:40 UTC
</div>
</div>
</body>

View File

@ -601,6 +601,14 @@ type EmptyDirVolumeSource struct {
// The default is "" which means to use the node's default medium.
// +optional
Medium StorageMedium
// Total amount of local storage required for this EmptyDir volume.
// The size limit is also applicable for memory medium.
// The maximum usage on memory medium EmptyDir would be the minimum value between
// the SizeLimit specified here and the sum of memory limits of all containers in a pod.
// The default is nil which means that the limit is undefined.
// More info: http://kubernetes.io/docs/user-guide/volumes#emptydir
// +optional
SizeLimit resource.Quantity
}
// StorageMedium defines ways that storage can be allocated to a volume.
@ -3017,6 +3025,12 @@ const (
ResourceMemory ResourceName = "memory"
// Volume size, in bytes (e,g. 5Gi = 5GiB = 5 * 1024 * 1024 * 1024)
ResourceStorage ResourceName = "storage"
// Local Storage for overlay filesystem, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// The resource name for ResourceStorageOverlay is alpha and it can change across releases.
ResourceStorageOverlay ResourceName = "storage.kubernetes.io/overlay"
// Local Storage for scratch space, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// The resource name for ResourceStorageScratch is alpha and it can change across releases.
ResourceStorageScratch ResourceName = "storage.kubernetes.io/scratch"
// NVIDIA GPU, in devices. Alpha, might change: although fractional and allowing values >1, only one whole device per node is assigned.
ResourceNvidiaGPU ResourceName = "alpha.kubernetes.io/nvidia-gpu"
// Number of Pods that may be running on this Node: see ResourcePods

File diff suppressed because it is too large Load Diff

View File

@ -761,6 +761,15 @@ message EmptyDirVolumeSource {
// More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
// +optional
optional string medium = 1;
// Total amount of local storage required for this EmptyDir volume.
// The size limit is also applicable for memory medium.
// The maximum usage on memory medium EmptyDir would be the minimum value between
// the SizeLimit specified here and the sum of memory limits of all containers in a pod.
// The default is nil which means that the limit is undefined.
// More info: http://kubernetes.io/docs/user-guide/volumes#emptydir
// +optional
optional k8s.io.apimachinery.pkg.api.resource.Quantity sizeLimit = 2;
}
// EndpointAddress is a tuple that describes single IP address.

View File

@ -11220,13 +11220,14 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [1]bool
var yyq2 [2]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[0] = x.Medium != ""
yyq2[1] = true
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(1)
r.EncodeArrayStart(2)
} else {
yynn2 = 0
for _, b := range yyq2 {
@ -11252,6 +11253,39 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
x.Medium.CodecEncodeSelf(e)
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[1] {
yy7 := &x.SizeLimit
yym8 := z.EncBinary()
_ = yym8
if false {
} else if z.HasExtensions() && z.EncExt(yy7) {
} else if !yym8 && z.IsJSONHandle() {
z.EncJSONMarshal(yy7)
} else {
z.EncFallback(yy7)
}
} else {
r.EncodeNil()
}
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("sizeLimit"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yy9 := &x.SizeLimit
yym10 := z.EncBinary()
_ = yym10
if false {
} else if z.HasExtensions() && z.EncExt(yy9) {
} else if !yym10 && z.IsJSONHandle() {
z.EncJSONMarshal(yy9)
} else {
z.EncFallback(yy9)
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
@ -11320,6 +11354,21 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromMap(l int, d *codec1978.Decode
yyv4 := &x.Medium
yyv4.CodecDecodeSelf(d)
}
case "sizeLimit":
if r.TryDecodeAsNil() {
x.SizeLimit = pkg3_resource.Quantity{}
} else {
yyv5 := &x.SizeLimit
yym6 := z.DecBinary()
_ = yym6
if false {
} else if z.HasExtensions() && z.DecExt(yyv5) {
} else if !yym6 && z.IsJSONHandle() {
z.DecJSONUnmarshal(yyv5)
} else {
z.DecFallback(yyv5, false)
}
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
@ -11331,16 +11380,16 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Deco
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj5 int
var yyb5 bool
var yyhl5 bool = l >= 0
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
var yyj7 int
var yyb7 bool
var yyhl7 bool = l >= 0
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb5 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb5 {
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -11348,21 +11397,46 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Deco
if r.TryDecodeAsNil() {
x.Medium = ""
} else {
yyv6 := &x.Medium
yyv6.CodecDecodeSelf(d)
yyv8 := &x.Medium
yyv8.CodecDecodeSelf(d)
}
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb7 = r.CheckBreak()
}
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.SizeLimit = pkg3_resource.Quantity{}
} else {
yyv9 := &x.SizeLimit
yym10 := z.DecBinary()
_ = yym10
if false {
} else if z.HasExtensions() && z.DecExt(yyv9) {
} else if !yym10 && z.IsJSONHandle() {
z.DecJSONUnmarshal(yyv9)
} else {
z.DecFallback(yyv9, false)
}
}
for {
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb5 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb5 {
if yyb7 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj5-1, "")
z.DecStructFieldNotFound(yyj7-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}

View File

@ -686,6 +686,14 @@ type EmptyDirVolumeSource struct {
// More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
// +optional
Medium StorageMedium `json:"medium,omitempty" protobuf:"bytes,1,opt,name=medium,casttype=StorageMedium"`
// Total amount of local storage required for this EmptyDir volume.
// The size limit is also applicable for memory medium.
// The maximum usage on memory medium EmptyDir would be the minimum value between
// the SizeLimit specified here and the sum of memory limits of all containers in a pod.
// The default is nil which means that the limit is undefined.
// More info: http://kubernetes.io/docs/user-guide/volumes#emptydir
// +optional
SizeLimit resource.Quantity `json:"sizeLimit,omitempty" protobuf:"bytes,2,opt,name=sizeLimit"`
}
// Represents a Glusterfs mount that lasts the lifetime of a pod.
@ -3455,6 +3463,12 @@ const (
ResourceMemory ResourceName = "memory"
// Volume size, in bytes (e,g. 5Gi = 5GiB = 5 * 1024 * 1024 * 1024)
ResourceStorage ResourceName = "storage"
// Local Storage for container overlay filesystem, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// The resource name for ResourceStorageOverlay is alpha and it can change across releases.
ResourceStorageOverlay ResourceName = "storage.kubernetes.io/overlay"
// Local Storage for scratch space, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// The resource name for ResourceStorageScratch is alpha and it can change across releases.
ResourceStorageScratch ResourceName = "storage.kubernetes.io/scratch"
// NVIDIA GPU, in devices. Alpha, might change: although fractional and allowing values >1, only one whole device per node is assigned.
ResourceNvidiaGPU ResourceName = "alpha.kubernetes.io/nvidia-gpu"
// Number of Pods that may be running on this Node: see ResourcePods

View File

@ -396,8 +396,9 @@ func (DownwardAPIVolumeSource) SwaggerDoc() map[string]string {
}
var map_EmptyDirVolumeSource = map[string]string{
"": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.",
"medium": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir",
"": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.",
"medium": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir",
"sizeLimit": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir",
}
func (EmptyDirVolumeSource) SwaggerDoc() map[string]string {

View File

@ -1236,6 +1236,7 @@ func Convert_api_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource(in *api.D
func autoConvert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVolumeSource, out *api.EmptyDirVolumeSource, s conversion.Scope) error {
out.Medium = api.StorageMedium(in.Medium)
out.SizeLimit = in.SizeLimit
return nil
}
@ -1246,6 +1247,7 @@ func Convert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVol
func autoConvert_api_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource(in *api.EmptyDirVolumeSource, out *EmptyDirVolumeSource, s conversion.Scope) error {
out.Medium = StorageMedium(in.Medium)
out.SizeLimit = in.SizeLimit
return nil
}

View File

@ -856,6 +856,7 @@ func DeepCopy_v1_EmptyDirVolumeSource(in interface{}, out interface{}, c *conver
in := in.(*EmptyDirVolumeSource)
out := out.(*EmptyDirVolumeSource)
*out = *in
out.SizeLimit = in.SizeLimit.DeepCopy()
return nil
}
}
@ -3549,7 +3550,9 @@ func DeepCopy_v1_VolumeSource(in interface{}, out interface{}, c *conversion.Clo
if in.EmptyDir != nil {
in, out := &in.EmptyDir, &out.EmptyDir
*out = new(EmptyDirVolumeSource)
**out = **in
if err := DeepCopy_v1_EmptyDirVolumeSource(*in, *out, c); err != nil {
return err
}
}
if in.GCEPersistentDisk != nil {
in, out := &in.GCEPersistentDisk, &out.GCEPersistentDisk

View File

@ -398,7 +398,12 @@ func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.E
allErrs := field.ErrorList{}
if source.EmptyDir != nil {
numVolumes++
// EmptyDirs have nothing to validate
if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
unsetSizeLimit := resource.Quantity{}
if unsetSizeLimit.Cmp(source.EmptyDir.SizeLimit) != 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("emptyDir").Child("sizeLimit"), "SizeLimit field disabled by feature-gate for EmptyDir volumes"))
}
}
}
if source.HostPath != nil {
if numVolumes > 0 {
@ -3638,6 +3643,9 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat
allErrs = append(allErrs, field.Invalid(limPath, quantity.String(), fmt.Sprintf("must be greater than or equal to %s request", resourceName)))
}
}
if resourceName == api.ResourceStorageOverlay && !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
allErrs = append(allErrs, field.Forbidden(limPath, "ResourceStorageOverlay field disabled by feature-gate for ResourceRequirements"))
}
}
for resourceName, quantity := range requirements.Requests {
fldPath := reqPath.Key(string(resourceName))

View File

@ -2374,6 +2374,62 @@ func TestValidateVolumes(t *testing.T) {
}
}
func TestAlphaLocalStorageCapacityIsolation(t *testing.T) {
testCases := []api.VolumeSource{
{EmptyDir: &api.EmptyDirVolumeSource{SizeLimit: *resource.NewQuantity(int64(5), resource.BinarySI)}},
}
// Enable alpha feature LocalStorageCapacityIsolation
err := utilfeature.DefaultFeatureGate.Set("LocalStorageCapacityIsolation=true")
if err != nil {
t.Errorf("Failed to enable feature gate for LocalStorageCapacityIsolation: %v", err)
return
}
for _, tc := range testCases {
if errs := validateVolumeSource(&tc, field.NewPath("spec")); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
// Disable alpha feature LocalStorageCapacityIsolation
err = utilfeature.DefaultFeatureGate.Set("LocalStorageCapacityIsolation=false")
if err != nil {
t.Errorf("Failed to disable feature gate for LocalStorageCapacityIsolation: %v", err)
return
}
for _, tc := range testCases {
if errs := validateVolumeSource(&tc, field.NewPath("spec")); len(errs) == 0 {
t.Errorf("expected failure: %v", errs)
}
}
containerLimitCase := api.ResourceRequirements{
Limits: api.ResourceList{
api.ResourceStorageOverlay: *resource.NewMilliQuantity(
int64(40000),
resource.BinarySI),
},
}
// Enable alpha feature LocalStorageCapacityIsolation
err = utilfeature.DefaultFeatureGate.Set("LocalStorageCapacityIsolation=true")
if err != nil {
t.Errorf("Failed to enable feature gate for LocalStorageCapacityIsolation: %v", err)
return
}
if errs := ValidateResourceRequirements(&containerLimitCase, field.NewPath("resources")); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
// Disable alpha feature LocalStorageCapacityIsolation
err = utilfeature.DefaultFeatureGate.Set("LocalStorageCapacityIsolation=false")
if err != nil {
t.Errorf("Failed to disable feature gate for LocalStorageCapacityIsolation: %v", err)
return
}
if errs := ValidateResourceRequirements(&containerLimitCase, field.NewPath("resources")); len(errs) == 0 {
t.Errorf("expected failure: %v", errs)
}
}
func TestValidatePorts(t *testing.T) {
successCase := []api.ContainerPort{
{Name: "abc", ContainerPort: 80, HostPort: 80, Protocol: "TCP"},

View File

@ -858,6 +858,7 @@ func DeepCopy_api_EmptyDirVolumeSource(in interface{}, out interface{}, c *conve
in := in.(*EmptyDirVolumeSource)
out := out.(*EmptyDirVolumeSource)
*out = *in
out.SizeLimit = in.SizeLimit.DeepCopy()
return nil
}
}
@ -3555,7 +3556,9 @@ func DeepCopy_api_VolumeSource(in interface{}, out interface{}, c *conversion.Cl
if in.EmptyDir != nil {
in, out := &in.EmptyDir, &out.EmptyDir
*out = new(EmptyDirVolumeSource)
**out = **in
if err := DeepCopy_api_EmptyDirVolumeSource(*in, *out, c); err != nil {
return err
}
}
if in.GCEPersistentDisk != nil {
in, out := &in.GCEPersistentDisk, &out.GCEPersistentDisk

View File

@ -102,6 +102,12 @@ const (
//
// A new volume type that supports local disks on a node.
PersistentLocalVolumes utilfeature.Feature = "PersistentLocalVolumes"
// owner: @jinxu
// alpha: v1.7
//
// New local storage types to support local storage capacity isolation
LocalStorageCapacityIsolation utilfeature.Feature = "LocalStorageCapacityIsolation"
)
func init() {
@ -123,6 +129,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
TaintBasedEvictions: {Default: false, PreRelease: utilfeature.Alpha},
RotateKubeletServerCertificate: {Default: false, PreRelease: utilfeature.Alpha},
PersistentLocalVolumes: {Default: false, PreRelease: utilfeature.Alpha},
LocalStorageCapacityIsolation: {Default: false, PreRelease: utilfeature.Alpha},
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:

View File

@ -601,6 +601,14 @@ type EmptyDirVolumeSource struct {
// The default is "" which means to use the node's default medium.
// +optional
Medium StorageMedium
// Total amount of local storage required for this EmptyDir volume.
// The size limit is also applicable for memory medium.
// The maximum usage on memory medium EmptyDir would be the minimum value between
// the SizeLimit specified here and the sum of memory limits of all containers in a pod.
// The default is nil which means that the limit is undefined.
// More info: http://kubernetes.io/docs/user-guide/volumes#emptydir
// +optional
SizeLimit resource.Quantity
}
// StorageMedium defines ways that storage can be allocated to a volume.
@ -3017,6 +3025,12 @@ const (
ResourceMemory ResourceName = "memory"
// Volume size, in bytes (e,g. 5Gi = 5GiB = 5 * 1024 * 1024 * 1024)
ResourceStorage ResourceName = "storage"
// Local Storage for overlay filesystem, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// The resource name for ResourceStorageOverlay is alpha and it can change across releases.
ResourceStorageOverlay ResourceName = "storage.kubernetes.io/overlay"
// Local Storage for scratch space, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// The resource name for ResourceStorageScratch is alpha and it can change across releases.
ResourceStorageScratch ResourceName = "storage.kubernetes.io/scratch"
// NVIDIA GPU, in devices. Alpha, might change: although fractional and allowing values >1, only one whole device per node is assigned.
ResourceNvidiaGPU ResourceName = "alpha.kubernetes.io/nvidia-gpu"
// Number of Pods that may be running on this Node: see ResourcePods

File diff suppressed because it is too large Load Diff

View File

@ -761,6 +761,15 @@ message EmptyDirVolumeSource {
// More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
// +optional
optional string medium = 1;
// Total amount of local storage required for this EmptyDir volume.
// The size limit is also applicable for memory medium.
// The maximum usage on memory medium EmptyDir would be the minimum value between
// the SizeLimit specified here and the sum of memory limits of all containers in a pod.
// The default is nil which means that the limit is undefined.
// More info: http://kubernetes.io/docs/user-guide/volumes#emptydir
// +optional
optional k8s.io.apimachinery.pkg.api.resource.Quantity sizeLimit = 2;
}
// EndpointAddress is a tuple that describes single IP address.

View File

@ -11220,13 +11220,14 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [1]bool
var yyq2 [2]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[0] = x.Medium != ""
yyq2[1] = true
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(1)
r.EncodeArrayStart(2)
} else {
yynn2 = 0
for _, b := range yyq2 {
@ -11252,6 +11253,39 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) {
x.Medium.CodecEncodeSelf(e)
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[1] {
yy7 := &x.SizeLimit
yym8 := z.EncBinary()
_ = yym8
if false {
} else if z.HasExtensions() && z.EncExt(yy7) {
} else if !yym8 && z.IsJSONHandle() {
z.EncJSONMarshal(yy7)
} else {
z.EncFallback(yy7)
}
} else {
r.EncodeNil()
}
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("sizeLimit"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yy9 := &x.SizeLimit
yym10 := z.EncBinary()
_ = yym10
if false {
} else if z.HasExtensions() && z.EncExt(yy9) {
} else if !yym10 && z.IsJSONHandle() {
z.EncJSONMarshal(yy9)
} else {
z.EncFallback(yy9)
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
@ -11320,6 +11354,21 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromMap(l int, d *codec1978.Decode
yyv4 := &x.Medium
yyv4.CodecDecodeSelf(d)
}
case "sizeLimit":
if r.TryDecodeAsNil() {
x.SizeLimit = pkg3_resource.Quantity{}
} else {
yyv5 := &x.SizeLimit
yym6 := z.DecBinary()
_ = yym6
if false {
} else if z.HasExtensions() && z.DecExt(yyv5) {
} else if !yym6 && z.IsJSONHandle() {
z.DecJSONUnmarshal(yyv5)
} else {
z.DecFallback(yyv5, false)
}
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
@ -11331,16 +11380,16 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Deco
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj5 int
var yyb5 bool
var yyhl5 bool = l >= 0
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
var yyj7 int
var yyb7 bool
var yyhl7 bool = l >= 0
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb5 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb5 {
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -11348,21 +11397,46 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Deco
if r.TryDecodeAsNil() {
x.Medium = ""
} else {
yyv6 := &x.Medium
yyv6.CodecDecodeSelf(d)
yyv8 := &x.Medium
yyv8.CodecDecodeSelf(d)
}
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb7 = r.CheckBreak()
}
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.SizeLimit = pkg3_resource.Quantity{}
} else {
yyv9 := &x.SizeLimit
yym10 := z.DecBinary()
_ = yym10
if false {
} else if z.HasExtensions() && z.DecExt(yyv9) {
} else if !yym10 && z.IsJSONHandle() {
z.DecJSONUnmarshal(yyv9)
} else {
z.DecFallback(yyv9, false)
}
}
for {
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb5 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb5 {
if yyb7 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj5-1, "")
z.DecStructFieldNotFound(yyj7-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}

View File

@ -686,6 +686,14 @@ type EmptyDirVolumeSource struct {
// More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
// +optional
Medium StorageMedium `json:"medium,omitempty" protobuf:"bytes,1,opt,name=medium,casttype=StorageMedium"`
// Total amount of local storage required for this EmptyDir volume.
// The size limit is also applicable for memory medium.
// The maximum usage on memory medium EmptyDir would be the minimum value between
// the SizeLimit specified here and the sum of memory limits of all containers in a pod.
// The default is nil which means that the limit is undefined.
// More info: http://kubernetes.io/docs/user-guide/volumes#emptydir
// +optional
SizeLimit resource.Quantity `json:"sizeLimit,omitempty" protobuf:"bytes,2,opt,name=sizeLimit"`
}
// Represents a Glusterfs mount that lasts the lifetime of a pod.
@ -3455,6 +3463,12 @@ const (
ResourceMemory ResourceName = "memory"
// Volume size, in bytes (e,g. 5Gi = 5GiB = 5 * 1024 * 1024 * 1024)
ResourceStorage ResourceName = "storage"
// Local Storage for container overlay filesystem, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// The resource name for ResourceStorageOverlay is alpha and it can change across releases.
ResourceStorageOverlay ResourceName = "storage.kubernetes.io/overlay"
// Local Storage for scratch space, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// The resource name for ResourceStorageScratch is alpha and it can change across releases.
ResourceStorageScratch ResourceName = "storage.kubernetes.io/scratch"
// NVIDIA GPU, in devices. Alpha, might change: although fractional and allowing values >1, only one whole device per node is assigned.
ResourceNvidiaGPU ResourceName = "alpha.kubernetes.io/nvidia-gpu"
// Number of Pods that may be running on this Node: see ResourcePods

View File

@ -396,8 +396,9 @@ func (DownwardAPIVolumeSource) SwaggerDoc() map[string]string {
}
var map_EmptyDirVolumeSource = map[string]string{
"": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.",
"medium": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir",
"": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.",
"medium": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir",
"sizeLimit": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir",
}
func (EmptyDirVolumeSource) SwaggerDoc() map[string]string {

View File

@ -1236,6 +1236,7 @@ func Convert_api_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource(in *api.D
func autoConvert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVolumeSource, out *api.EmptyDirVolumeSource, s conversion.Scope) error {
out.Medium = api.StorageMedium(in.Medium)
out.SizeLimit = in.SizeLimit
return nil
}
@ -1246,6 +1247,7 @@ func Convert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVol
func autoConvert_api_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource(in *api.EmptyDirVolumeSource, out *EmptyDirVolumeSource, s conversion.Scope) error {
out.Medium = StorageMedium(in.Medium)
out.SizeLimit = in.SizeLimit
return nil
}

View File

@ -856,6 +856,7 @@ func DeepCopy_v1_EmptyDirVolumeSource(in interface{}, out interface{}, c *conver
in := in.(*EmptyDirVolumeSource)
out := out.(*EmptyDirVolumeSource)
*out = *in
out.SizeLimit = in.SizeLimit.DeepCopy()
return nil
}
}
@ -3549,7 +3550,9 @@ func DeepCopy_v1_VolumeSource(in interface{}, out interface{}, c *conversion.Clo
if in.EmptyDir != nil {
in, out := &in.EmptyDir, &out.EmptyDir
*out = new(EmptyDirVolumeSource)
**out = **in
if err := DeepCopy_v1_EmptyDirVolumeSource(*in, *out, c); err != nil {
return err
}
}
if in.GCEPersistentDisk != nil {
in, out := &in.GCEPersistentDisk, &out.GCEPersistentDisk

View File

@ -858,6 +858,7 @@ func DeepCopy_api_EmptyDirVolumeSource(in interface{}, out interface{}, c *conve
in := in.(*EmptyDirVolumeSource)
out := out.(*EmptyDirVolumeSource)
*out = *in
out.SizeLimit = in.SizeLimit.DeepCopy()
return nil
}
}
@ -3555,7 +3556,9 @@ func DeepCopy_api_VolumeSource(in interface{}, out interface{}, c *conversion.Cl
if in.EmptyDir != nil {
in, out := &in.EmptyDir, &out.EmptyDir
*out = new(EmptyDirVolumeSource)
**out = **in
if err := DeepCopy_api_EmptyDirVolumeSource(*in, *out, c); err != nil {
return err
}
}
if in.GCEPersistentDisk != nil {
in, out := &in.GCEPersistentDisk, &out.GCEPersistentDisk