Merge pull request #63233 from lichuqiang/provision_api

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

API change for volume topology aware dynamic provisioning

**What this PR does / why we need it**:

Split PR https://github.com/kubernetes/kubernetes/pull/63193 for better review
part 2: API change

Previous: https://github.com/kubernetes/kubernetes/pull/63232
Next: https://github.com/kubernetes/kubernetes/pull/63193

**Which issue(s) this PR fixes** 
Feature: https://github.com/kubernetes/features/issues/561
Design: https://github.com/kubernetes/community/issues/2168

**Special notes for your reviewer**:
/sig storage
/sig scheduling
/assign @msau42 @jsafrane @thockin 


**Release note**:

```release-note
API change for volume topology aware dynamic provisioning
```
This commit is contained in:
Kubernetes Submit Queue 2018-06-05 00:56:17 -07:00 committed by GitHub
commit 77d996b278
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 2419 additions and 974 deletions

View File

@ -78477,7 +78477,7 @@
}
},
"io.k8s.api.core.v1.NodeSelectorTerm": {
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"properties": {
"matchExpressions": {
"description": "A list of node selector requirements by node's labels.",
@ -80948,6 +80948,38 @@
}
}
},
"io.k8s.api.core.v1.TopologySelectorLabelRequirement": {
"description": "A topology selector requirement is a selector that matches given label. This is an alpha feature and may change in the future.",
"required": [
"key",
"values"
],
"properties": {
"key": {
"description": "The label key that the selector applies to.",
"type": "string"
},
"values": {
"description": "An array of string values. One value must match the label to be selected. Each entry in Values is ORed.",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"io.k8s.api.core.v1.TopologySelectorTerm": {
"description": "A topology selector term represents the result of label queries. A null or empty topology selector term matches no objects. The requirements of them are ANDed. It provides a subset of functionality as NodeSelectorTerm. This is an alpha feature and may change in the future.",
"properties": {
"matchLabelExpressions": {
"description": "A list of topology selector requirements by labels.",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.api.core.v1.TopologySelectorLabelRequirement"
}
}
}
},
"io.k8s.api.core.v1.Volume": {
"description": "Volume represents a named volume in a pod that may be accessed by any container in the pod.",
"required": [
@ -84727,6 +84759,13 @@
"description": "AllowVolumeExpansion shows whether the storage class allow volume expand",
"type": "boolean"
},
"allowedTopologies": {
"description": "Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature.",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.api.core.v1.TopologySelectorTerm"
}
},
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"
@ -84958,6 +84997,13 @@
"description": "AllowVolumeExpansion shows whether the storage class allow volume expand",
"type": "boolean"
},
"allowedTopologies": {
"description": "Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature.",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.api.core.v1.TopologySelectorTerm"
}
},
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"

View File

@ -8477,7 +8477,7 @@
},
"v1.NodeSelectorTerm": {
"id": "v1.NodeSelectorTerm",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"properties": {
"matchExpressions": {
"type": "array",

View File

@ -6111,7 +6111,7 @@
},
"v1.NodeSelectorTerm": {
"id": "v1.NodeSelectorTerm",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"properties": {
"matchExpressions": {
"type": "array",

View File

@ -8477,7 +8477,7 @@
},
"v1.NodeSelectorTerm": {
"id": "v1.NodeSelectorTerm",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"properties": {
"matchExpressions": {
"type": "array",

View File

@ -3451,7 +3451,7 @@
},
"v1.NodeSelectorTerm": {
"id": "v1.NodeSelectorTerm",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"properties": {
"matchExpressions": {
"type": "array",

View File

@ -3506,7 +3506,7 @@
},
"v1.NodeSelectorTerm": {
"id": "v1.NodeSelectorTerm",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"properties": {
"matchExpressions": {
"type": "array",

View File

@ -3506,7 +3506,7 @@
},
"v1.NodeSelectorTerm": {
"id": "v1.NodeSelectorTerm",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"properties": {
"matchExpressions": {
"type": "array",

View File

@ -9119,7 +9119,7 @@
},
"v1.NodeSelectorTerm": {
"id": "v1.NodeSelectorTerm",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"properties": {
"matchExpressions": {
"type": "array",

View File

@ -818,6 +818,13 @@
"volumeBindingMode": {
"$ref": "v1.VolumeBindingMode",
"description": "VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. When unset, VolumeBindingImmediate is used. This field is alpha-level and is only honored by servers that enable the VolumeScheduling feature."
},
"allowedTopologies": {
"type": "array",
"items": {
"$ref": "v1.TopologySelectorTerm"
},
"description": "Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature."
}
}
},
@ -1067,6 +1074,40 @@
"id": "v1.VolumeBindingMode",
"properties": {}
},
"v1.TopologySelectorTerm": {
"id": "v1.TopologySelectorTerm",
"description": "A topology selector term represents the result of label queries. A null or empty topology selector term matches no objects. The requirements of them are ANDed. It provides a subset of functionality as NodeSelectorTerm. This is an alpha feature and may change in the future.",
"properties": {
"matchLabelExpressions": {
"type": "array",
"items": {
"$ref": "v1.TopologySelectorLabelRequirement"
},
"description": "A list of topology selector requirements by labels."
}
}
},
"v1.TopologySelectorLabelRequirement": {
"id": "v1.TopologySelectorLabelRequirement",
"description": "A topology selector requirement is a selector that matches given label. This is an alpha feature and may change in the future.",
"required": [
"key",
"values"
],
"properties": {
"key": {
"type": "string",
"description": "The label key that the selector applies to."
},
"values": {
"type": "array",
"items": {
"type": "string"
},
"description": "An array of string values. One value must match the label to be selected. Each entry in Values is ORed."
}
}
},
"v1.WatchEvent": {
"id": "v1.WatchEvent",
"required": [

View File

@ -1512,6 +1512,13 @@
"volumeBindingMode": {
"$ref": "v1beta1.VolumeBindingMode",
"description": "VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. When unset, VolumeBindingImmediate is used. This field is alpha-level and is only honored by servers that enable the VolumeScheduling feature."
},
"allowedTopologies": {
"type": "array",
"items": {
"$ref": "v1.TopologySelectorTerm"
},
"description": "Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature."
}
}
},
@ -1761,6 +1768,40 @@
"id": "v1beta1.VolumeBindingMode",
"properties": {}
},
"v1.TopologySelectorTerm": {
"id": "v1.TopologySelectorTerm",
"description": "A topology selector term represents the result of label queries. A null or empty topology selector term matches no objects. The requirements of them are ANDed. It provides a subset of functionality as NodeSelectorTerm. This is an alpha feature and may change in the future.",
"properties": {
"matchLabelExpressions": {
"type": "array",
"items": {
"$ref": "v1.TopologySelectorLabelRequirement"
},
"description": "A list of topology selector requirements by labels."
}
}
},
"v1.TopologySelectorLabelRequirement": {
"id": "v1.TopologySelectorLabelRequirement",
"description": "A topology selector requirement is a selector that matches given label. This is an alpha feature and may change in the future.",
"required": [
"key",
"values"
],
"properties": {
"key": {
"type": "string",
"description": "The label key that the selector applies to."
},
"values": {
"type": "array",
"items": {
"type": "string"
},
"description": "An array of string values. One value must match the label to be selected. Each entry in Values is ORed."
}
}
},
"v1.WatchEvent": {
"id": "v1.WatchEvent",
"required": [

View File

@ -20110,7 +20110,7 @@
},
"v1.NodeSelectorTerm": {
"id": "v1.NodeSelectorTerm",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"properties": {
"matchExpressions": {
"type": "array",

View File

@ -512,7 +512,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<div class="sect2">
<h3 id="_v1_nodeselectorterm">v1.NodeSelectorTerm</h3>
<div class="paragraph">
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed.</p>
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>

View File

@ -623,7 +623,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<div class="sect2">
<h3 id="_v1_nodeselectorterm">v1.NodeSelectorTerm</h3>
<div class="paragraph">
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed.</p>
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>

View File

@ -515,7 +515,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<div class="sect2">
<h3 id="_v1_nodeselectorterm">v1.NodeSelectorTerm</h3>
<div class="paragraph">
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed.</p>
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>

View File

@ -488,7 +488,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<div class="sect2">
<h3 id="_v1_nodeselectorterm">v1.NodeSelectorTerm</h3>
<div class="paragraph">
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed.</p>
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>

View File

@ -488,7 +488,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<div class="sect2">
<h3 id="_v1_nodeselectorterm">v1.NodeSelectorTerm</h3>
<div class="paragraph">
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed.</p>
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>

View File

@ -488,7 +488,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<div class="sect2">
<h3 id="_v1_nodeselectorterm">v1.NodeSelectorTerm</h3>
<div class="paragraph">
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed.</p>
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>

View File

@ -740,7 +740,7 @@ Examples: <code>/foo</code> would allow <code>/foo</code>, <code>/foo/</code> an
<div class="sect2">
<h3 id="_v1_nodeselectorterm">v1.NodeSelectorTerm</h3>
<div class="paragraph">
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed.</p>
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>

View File

@ -559,6 +559,47 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_topologyselectorlabelrequirement">v1.TopologySelectorLabelRequirement</h3>
<div class="paragraph">
<p>A topology selector requirement is a selector that matches given label. This is an alpha feature and may change in the future.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">key</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The label key that the selector applies to.</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</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">values</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">An array of string values. One value must match the label to be selected. Each entry in Values is ORed.</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>
</div>
<div class="sect2">
<h3 id="_v1_statusdetails">v1.StatusDetails</h3>
@ -1003,6 +1044,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_volumebindingmode">v1.VolumeBindingMode</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">allowedTopologies</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature.</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"><a href="#_v1_topologyselectorterm">v1.TopologySelectorTerm</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
@ -1230,6 +1278,40 @@ When an object is created, the system will populate this list with the current s
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_topologyselectorterm">v1.TopologySelectorTerm</h3>
<div class="paragraph">
<p>A topology selector term represents the result of label queries. A null or empty topology selector term matches no objects. The requirements of them are ANDed. It provides a subset of functionality as NodeSelectorTerm. This is an alpha feature and may change in the future.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">matchLabelExpressions</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A list of topology selector requirements by labels.</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"><a href="#_v1_topologyselectorlabelrequirement">v1.TopologySelectorLabelRequirement</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_persistentvolumereclaimpolicy">v1.PersistentVolumeReclaimPolicy</h3>

View File

@ -779,6 +779,40 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<div class="sect2">
<h3 id="_v1_persistentvolumereclaimpolicy">v1.PersistentVolumeReclaimPolicy</h3>
</div>
<div class="sect2">
<h3 id="_v1_topologyselectorterm">v1.TopologySelectorTerm</h3>
<div class="paragraph">
<p>A topology selector term represents the result of label queries. A null or empty topology selector term matches no objects. The requirements of them are ANDed. It provides a subset of functionality as NodeSelectorTerm. This is an alpha feature and may change in the future.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">matchLabelExpressions</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A list of topology selector requirements by labels.</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"><a href="#_v1_topologyselectorlabelrequirement">v1.TopologySelectorLabelRequirement</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1beta1_volumeattachmentlist">v1beta1.VolumeAttachmentList</h3>
@ -1041,6 +1075,47 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_topologyselectorlabelrequirement">v1.TopologySelectorLabelRequirement</h3>
<div class="paragraph">
<p>A topology selector requirement is a selector that matches given label. This is an alpha feature and may change in the future.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">key</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The label key that the selector applies to.</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</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">values</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">An array of string values. One value must match the label to be selected. Each entry in Values is ORed.</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>
</div>
<div class="sect2">
<h3 id="_v1_initializer">v1.Initializer</h3>
@ -1075,6 +1150,47 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1beta1_volumeerror">v1beta1.VolumeError</h3>
<div class="paragraph">
<p>VolumeError captures an error encountered during a volume operation.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">time</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Time the error was encountered.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">message</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">String detailing the error encountered during Attach or Detach operation. This string maybe logged, so it should not contain sensitive information.</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>
</div>
<div class="sect2">
<h3 id="_v1beta1_storageclass">v1beta1.StorageClass</h3>
@ -1165,45 +1281,11 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_volumebindingmode">v1beta1.VolumeBindingMode</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1beta1_volumeerror">v1beta1.VolumeError</h3>
<div class="paragraph">
<p>VolumeError captures an error encountered during a volume operation.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">time</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Time the error was encountered.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">allowedTopologies</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">message</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">String detailing the error encountered during Attach or Detach operation. This string maybe logged, so it should not contain sensitive information.</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"><p class="tableblock"><a href="#_v1_topologyselectorterm">v1.TopologySelectorTerm</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>

View File

@ -6587,7 +6587,7 @@ Examples:<br>
<div class="sect2">
<h3 id="_v1_nodeselectorterm">v1.NodeSelectorTerm</h3>
<div class="paragraph">
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed.</p>
<p>A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>

View File

@ -2166,6 +2166,7 @@ type NodeSelector struct {
// A null or empty node selector term matches no objects. The requirements of
// them are ANDed.
// The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
type NodeSelectorTerm struct {
// A list of node selector requirements by node's labels.
MatchExpressions []NodeSelectorRequirement
@ -2203,6 +2204,27 @@ const (
NodeSelectorOpLt NodeSelectorOperator = "Lt"
)
// A topology selector term represents the result of label queries.
// A null or empty topology selector term matches no objects.
// The requirements of them are ANDed.
// It provides a subset of functionality as NodeSelectorTerm.
// This is an alpha feature and may change in the future.
type TopologySelectorTerm struct {
// A list of topology selector requirements by labels.
// +optional
MatchLabelExpressions []TopologySelectorLabelRequirement
}
// A topology selector requirement is a selector that matches given label.
// This is an alpha feature and may change in the future.
type TopologySelectorLabelRequirement struct {
// The label key that the selector applies to.
Key string
// An array of string values. One value must match the label to be selected.
// Each entry in Values is ORed.
Values []string
}
// Affinity is a group of affinity scheduling rules.
type Affinity struct {
// Describes node affinity scheduling rules for the pod.

View File

@ -316,6 +316,50 @@ func MatchNodeSelectorTerms(
return false
}
// TopologySelectorRequirementsAsSelector converts the []TopologySelectorLabelRequirement api type into a struct
// that implements labels.Selector.
func TopologySelectorRequirementsAsSelector(tsm []v1.TopologySelectorLabelRequirement) (labels.Selector, error) {
if len(tsm) == 0 {
return labels.Nothing(), nil
}
selector := labels.NewSelector()
for _, expr := range tsm {
r, err := labels.NewRequirement(expr.Key, selection.In, expr.Values)
if err != nil {
return nil, err
}
selector = selector.Add(*r)
}
return selector, nil
}
// MatchTopologySelectorTerms checks whether given labels match topology selector terms in ORed;
// nil or empty term matches no objects; while empty term list matches all objects.
func MatchTopologySelectorTerms(topologySelectorTerms []v1.TopologySelectorTerm, lbls labels.Set) bool {
if len(topologySelectorTerms) == 0 {
// empty term list matches all objects
return true
}
for _, req := range topologySelectorTerms {
// nil or empty term selects no objects
if len(req.MatchLabelExpressions) == 0 {
continue
}
labelSelector, err := TopologySelectorRequirementsAsSelector(req.MatchLabelExpressions)
if err != nil || !labelSelector.Matches(lbls) {
continue
}
return true
}
return false
}
// AddOrUpdateTolerationInPodSpec tries to add a toleration to the toleration list in PodSpec.
// Returns true if something was updated, false otherwise.
func AddOrUpdateTolerationInPodSpec(spec *v1.PodSpec, toleration *v1.Toleration) bool {

View File

@ -301,6 +301,71 @@ func TestNodeSelectorRequirementsAsSelector(t *testing.T) {
}
}
func TestTopologySelectorRequirementsAsSelector(t *testing.T) {
mustParse := func(s string) labels.Selector {
out, e := labels.Parse(s)
if e != nil {
panic(e)
}
return out
}
tc := []struct {
in []v1.TopologySelectorLabelRequirement
out labels.Selector
expectErr bool
}{
{in: nil, out: labels.Nothing()},
{in: []v1.TopologySelectorLabelRequirement{}, out: labels.Nothing()},
{
in: []v1.TopologySelectorLabelRequirement{{
Key: "foo",
Values: []string{"bar", "baz"},
}},
out: mustParse("foo in (baz,bar)"),
},
{
in: []v1.TopologySelectorLabelRequirement{{
Key: "foo",
Values: []string{},
}},
expectErr: true,
},
{
in: []v1.TopologySelectorLabelRequirement{
{
Key: "foo",
Values: []string{"bar", "baz"},
},
{
Key: "invalid",
Values: []string{},
},
},
expectErr: true,
},
{
in: []v1.TopologySelectorLabelRequirement{{
Key: "/invalidkey",
Values: []string{"bar", "baz"},
}},
expectErr: true,
},
}
for i, tc := range tc {
out, err := TopologySelectorRequirementsAsSelector(tc.in)
if err == nil && tc.expectErr {
t.Errorf("[%v]expected error but got none.", i)
}
if err != nil && !tc.expectErr {
t.Errorf("[%v]did not expect error but got: %v", i, err)
}
if !reflect.DeepEqual(out, tc.out) {
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
}
}
}
func TestTolerationsTolerateTaintsWithFilter(t *testing.T) {
testCases := []struct {
description string
@ -792,3 +857,161 @@ func TestMatchNodeSelectorTerms(t *testing.T) {
})
}
}
func TestMatchTopologySelectorTerms(t *testing.T) {
type args struct {
topologySelectorTerms []v1.TopologySelectorTerm
labels labels.Set
}
tests := []struct {
name string
args args
want bool
}{
{
name: "nil term list",
args: args{
topologySelectorTerms: nil,
labels: nil,
},
want: true,
},
{
name: "nil term",
args: args{
topologySelectorTerms: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{},
},
},
labels: nil,
},
want: false,
},
{
name: "label matches MatchLabelExpressions terms",
args: args{
topologySelectorTerms: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{{
Key: "label_1",
Values: []string{"label_1_val"},
}},
},
},
labels: map[string]string{"label_1": "label_1_val"},
},
want: true,
},
{
name: "label does not match MatchLabelExpressions terms",
args: args{
topologySelectorTerms: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{{
Key: "label_1",
Values: []string{"label_1_val"},
}},
},
},
labels: map[string]string{"label_1": "label_1_val-failed"},
},
want: false,
},
{
name: "multi-values in one requirement, one matched",
args: args{
topologySelectorTerms: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{{
Key: "label_1",
Values: []string{"label_1_val1", "label_1_val2"},
}},
},
},
labels: map[string]string{"label_1": "label_1_val2"},
},
want: true,
},
{
name: "multi-terms was set, one matched",
args: args{
topologySelectorTerms: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{{
Key: "label_1",
Values: []string{"label_1_val"},
}},
},
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{{
Key: "label_2",
Values: []string{"label_2_val"},
}},
},
},
labels: map[string]string{
"label_2": "label_2_val",
},
},
want: true,
},
{
name: "multi-requirement in one term, fully matched",
args: args{
topologySelectorTerms: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: "label_1",
Values: []string{"label_1_val"},
},
{
Key: "label_2",
Values: []string{"label_2_val"},
},
},
},
},
labels: map[string]string{
"label_1": "label_1_val",
"label_2": "label_2_val",
},
},
want: true,
},
{
name: "multi-requirement in one term, partial matched",
args: args{
topologySelectorTerms: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: "label_1",
Values: []string{"label_1_val"},
},
{
Key: "label_2",
Values: []string{"label_2_val"},
},
},
},
},
labels: map[string]string{
"label_1": "label_1_val-failed",
"label_2": "label_2_val",
},
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := MatchTopologySelectorTerms(tt.args.topologySelectorTerms, tt.args.labels); got != tt.want {
t.Errorf("MatchTopologySelectorTermsORed() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -408,6 +408,10 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_core_Taint_To_v1_Taint,
Convert_v1_Toleration_To_core_Toleration,
Convert_core_Toleration_To_v1_Toleration,
Convert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement,
Convert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement,
Convert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm,
Convert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm,
Convert_v1_Volume_To_core_Volume,
Convert_core_Volume_To_v1_Volume,
Convert_v1_VolumeDevice_To_core_VolumeDevice,
@ -5541,6 +5545,48 @@ func Convert_core_Toleration_To_v1_Toleration(in *core.Toleration, out *v1.Toler
return autoConvert_core_Toleration_To_v1_Toleration(in, out, s)
}
func autoConvert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement(in *v1.TopologySelectorLabelRequirement, out *core.TopologySelectorLabelRequirement, s conversion.Scope) error {
out.Key = in.Key
out.Values = *(*[]string)(unsafe.Pointer(&in.Values))
return nil
}
// Convert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement is an autogenerated conversion function.
func Convert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement(in *v1.TopologySelectorLabelRequirement, out *core.TopologySelectorLabelRequirement, s conversion.Scope) error {
return autoConvert_v1_TopologySelectorLabelRequirement_To_core_TopologySelectorLabelRequirement(in, out, s)
}
func autoConvert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement(in *core.TopologySelectorLabelRequirement, out *v1.TopologySelectorLabelRequirement, s conversion.Scope) error {
out.Key = in.Key
out.Values = *(*[]string)(unsafe.Pointer(&in.Values))
return nil
}
// Convert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement is an autogenerated conversion function.
func Convert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement(in *core.TopologySelectorLabelRequirement, out *v1.TopologySelectorLabelRequirement, s conversion.Scope) error {
return autoConvert_core_TopologySelectorLabelRequirement_To_v1_TopologySelectorLabelRequirement(in, out, s)
}
func autoConvert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm(in *v1.TopologySelectorTerm, out *core.TopologySelectorTerm, s conversion.Scope) error {
out.MatchLabelExpressions = *(*[]core.TopologySelectorLabelRequirement)(unsafe.Pointer(&in.MatchLabelExpressions))
return nil
}
// Convert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm is an autogenerated conversion function.
func Convert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm(in *v1.TopologySelectorTerm, out *core.TopologySelectorTerm, s conversion.Scope) error {
return autoConvert_v1_TopologySelectorTerm_To_core_TopologySelectorTerm(in, out, s)
}
func autoConvert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm(in *core.TopologySelectorTerm, out *v1.TopologySelectorTerm, s conversion.Scope) error {
out.MatchLabelExpressions = *(*[]v1.TopologySelectorLabelRequirement)(unsafe.Pointer(&in.MatchLabelExpressions))
return nil
}
// Convert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm is an autogenerated conversion function.
func Convert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm(in *core.TopologySelectorTerm, out *v1.TopologySelectorTerm, s conversion.Scope) error {
return autoConvert_core_TopologySelectorTerm_To_v1_TopologySelectorTerm(in, out, s)
}
func autoConvert_v1_Volume_To_core_Volume(in *v1.Volume, out *core.Volume, s conversion.Scope) error {
out.Name = in.Name
if err := Convert_v1_VolumeSource_To_core_VolumeSource(&in.VolumeSource, &out.VolumeSource, s); err != nil {

View File

@ -3104,6 +3104,32 @@ func ValidateNodeSelector(nodeSelector *core.NodeSelector, fldPath *field.Path)
return allErrs
}
// validateTopologySelectorLabelRequirement tests that the specified TopologySelectorLabelRequirement fields has valid data
func validateTopologySelectorLabelRequirement(rq core.TopologySelectorLabelRequirement, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(rq.Values) == 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("values"), "must specify as least one value"))
}
allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(rq.Key, fldPath.Child("key"))...)
return allErrs
}
// ValidateTopologySelectorTerm tests that the specified topology selector term has valid data
func ValidateTopologySelectorTerm(term core.TopologySelectorTerm, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if utilfeature.DefaultFeatureGate.Enabled(features.DynamicProvisioningScheduling) {
for i, req := range term.MatchLabelExpressions {
allErrs = append(allErrs, validateTopologySelectorLabelRequirement(req, fldPath.Child("matchLabelExpressions").Index(i))...)
}
} else if len(term.MatchLabelExpressions) != 0 {
allErrs = append(allErrs, field.Forbidden(fldPath, "field is disabled by feature-gate DynamicProvisioningScheduling"))
}
return allErrs
}
// ValidateAvoidPodsInNodeAnnotations tests that the serialized AvoidPods in Node.Annotations has valid data
func ValidateAvoidPodsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}

View File

@ -5567,6 +5567,50 @@ func (in *Toleration) DeepCopy() *Toleration {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TopologySelectorLabelRequirement) DeepCopyInto(out *TopologySelectorLabelRequirement) {
*out = *in
if in.Values != nil {
in, out := &in.Values, &out.Values
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologySelectorLabelRequirement.
func (in *TopologySelectorLabelRequirement) DeepCopy() *TopologySelectorLabelRequirement {
if in == nil {
return nil
}
out := new(TopologySelectorLabelRequirement)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TopologySelectorTerm) DeepCopyInto(out *TopologySelectorTerm) {
*out = *in
if in.MatchLabelExpressions != nil {
in, out := &in.MatchLabelExpressions, &out.MatchLabelExpressions
*out = make([]TopologySelectorLabelRequirement, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologySelectorTerm.
func (in *TopologySelectorTerm) DeepCopy() *TopologySelectorTerm {
if in == nil {
return nil
}
out := new(TopologySelectorTerm)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Volume) DeepCopyInto(out *Volume) {
*out = *in

View File

@ -72,6 +72,14 @@ type StorageClass struct {
// the VolumeScheduling feature.
// +optional
VolumeBindingMode *VolumeBindingMode
// Restrict the node topologies where volumes can be dynamically provisioned.
// Each volume plugin defines its own supported topology specifications.
// An empty TopologySelectorTerm list means there is no topology restriction.
// This field is alpha-level and is only honored by servers that enable
// the DynamicProvisioningScheduling feature.
// +optional
AllowedTopologies []api.TopologySelectorTerm
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -39,6 +39,7 @@ go_test(
srcs = ["util_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/storage:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
],

View File

@ -27,4 +27,7 @@ func DropDisabledAlphaFields(class *storage.StorageClass) {
if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
class.VolumeBindingMode = nil
}
if !utilfeature.DefaultFeatureGate.Enabled(features.DynamicProvisioningScheduling) {
class.AllowedTopologies = nil
}
}

View File

@ -17,39 +17,60 @@ limitations under the License.
package util
import (
"reflect"
"testing"
utilfeature "k8s.io/apiserver/pkg/util/feature"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/storage"
)
func TestDropAlphaFields(t *testing.T) {
bindingMode := storage.VolumeBindingWaitForFirstConsumer
allowedTopologies := []api.TopologySelectorTerm{
{
MatchLabelExpressions: []api.TopologySelectorLabelRequirement{
{
Key: "kubernetes.io/hostname",
Values: []string{"node1"},
},
},
},
}
// Test that field gets dropped when feature gate is not set
if err := utilfeature.DefaultFeatureGate.Set("VolumeScheduling=false"); err != nil {
t.Fatalf("Failed to set feature gate for VolumeScheduling: %v", err)
if err := utilfeature.DefaultFeatureGate.Set("VolumeScheduling=false,DynamicProvisioningScheduling=false"); err != nil {
t.Fatalf("Failed to set feature gate for VolumeScheduling or DynamicProvisioningScheduling: %v", err)
}
class := &storage.StorageClass{
VolumeBindingMode: &bindingMode,
AllowedTopologies: allowedTopologies,
}
DropDisabledAlphaFields(class)
if class.VolumeBindingMode != nil {
t.Errorf("VolumeBindingMode field didn't get dropped: %+v", class.VolumeBindingMode)
}
if class.AllowedTopologies != nil {
t.Errorf("AllowedTopologies field didn't get dropped: %+v", class.AllowedTopologies)
}
// Test that field does not get dropped when feature gate is set
class = &storage.StorageClass{
VolumeBindingMode: &bindingMode,
AllowedTopologies: allowedTopologies,
}
if err := utilfeature.DefaultFeatureGate.Set("VolumeScheduling=true"); err != nil {
t.Fatalf("Failed to set feature gate for VolumeScheduling: %v", err)
if err := utilfeature.DefaultFeatureGate.Set("VolumeScheduling=true,DynamicProvisioningScheduling=true"); err != nil {
t.Fatalf("Failed to set feature gate for VolumeScheduling or DynamicProvisioningScheduling: %v", err)
}
DropDisabledAlphaFields(class)
if class.VolumeBindingMode != &bindingMode {
t.Errorf("VolumeBindingMode field got unexpectantly modified: %+v", class.VolumeBindingMode)
}
if err := utilfeature.DefaultFeatureGate.Set("VolumeScheduling=false"); err != nil {
t.Fatalf("Failed to disable feature gate for VolumeScheduling: %v", err)
if !reflect.DeepEqual(class.AllowedTopologies, allowedTopologies) {
t.Errorf("AllowedTopologies field got unexpectantly modified: %+v", class.AllowedTopologies)
}
if err := utilfeature.DefaultFeatureGate.Set("VolumeScheduling=false,DynamicProvisioningScheduling=false"); err != nil {
t.Fatalf("Failed to disable feature gate for VolumeScheduling or DynamicProvisioningScheduling: %v", err)
}
}

View File

@ -54,6 +54,7 @@ func autoConvert_v1_StorageClass_To_storage_StorageClass(in *v1.StorageClass, ou
out.MountOptions = *(*[]string)(unsafe.Pointer(&in.MountOptions))
out.AllowVolumeExpansion = (*bool)(unsafe.Pointer(in.AllowVolumeExpansion))
out.VolumeBindingMode = (*storage.VolumeBindingMode)(unsafe.Pointer(in.VolumeBindingMode))
out.AllowedTopologies = *(*[]core.TopologySelectorTerm)(unsafe.Pointer(&in.AllowedTopologies))
return nil
}
@ -70,6 +71,7 @@ func autoConvert_storage_StorageClass_To_v1_StorageClass(in *storage.StorageClas
out.MountOptions = *(*[]string)(unsafe.Pointer(&in.MountOptions))
out.AllowVolumeExpansion = (*bool)(unsafe.Pointer(in.AllowVolumeExpansion))
out.VolumeBindingMode = (*v1.VolumeBindingMode)(unsafe.Pointer(in.VolumeBindingMode))
out.AllowedTopologies = *(*[]core_v1.TopologySelectorTerm)(unsafe.Pointer(&in.AllowedTopologies))
return nil
}

View File

@ -66,6 +66,7 @@ func autoConvert_v1beta1_StorageClass_To_storage_StorageClass(in *v1beta1.Storag
out.MountOptions = *(*[]string)(unsafe.Pointer(&in.MountOptions))
out.AllowVolumeExpansion = (*bool)(unsafe.Pointer(in.AllowVolumeExpansion))
out.VolumeBindingMode = (*storage.VolumeBindingMode)(unsafe.Pointer(in.VolumeBindingMode))
out.AllowedTopologies = *(*[]core.TopologySelectorTerm)(unsafe.Pointer(&in.AllowedTopologies))
return nil
}
@ -82,6 +83,7 @@ func autoConvert_storage_StorageClass_To_v1beta1_StorageClass(in *storage.Storag
out.MountOptions = *(*[]string)(unsafe.Pointer(&in.MountOptions))
out.AllowVolumeExpansion = (*bool)(unsafe.Pointer(in.AllowVolumeExpansion))
out.VolumeBindingMode = (*v1beta1.VolumeBindingMode)(unsafe.Pointer(in.VolumeBindingMode))
out.AllowedTopologies = *(*[]v1.TopologySelectorTerm)(unsafe.Pointer(&in.AllowedTopologies))
return nil
}

View File

@ -47,6 +47,7 @@ func ValidateStorageClass(storageClass *storage.StorageClass) field.ErrorList {
allErrs = append(allErrs, validateReclaimPolicy(storageClass.ReclaimPolicy, field.NewPath("reclaimPolicy"))...)
allErrs = append(allErrs, validateAllowVolumeExpansion(storageClass.AllowVolumeExpansion, field.NewPath("allowVolumeExpansion"))...)
allErrs = append(allErrs, validateVolumeBindingMode(storageClass.VolumeBindingMode, field.NewPath("volumeBindingMode"))...)
allErrs = append(allErrs, validateAllowedTopologies(storageClass.AllowedTopologies, field.NewPath("allowedTopologies"))...)
return allErrs
}
@ -239,3 +240,22 @@ func validateVolumeBindingMode(mode *storage.VolumeBindingMode, fldPath *field.P
return allErrs
}
// validateAllowedTopology tests that AllowedTopologies specifies valid values.
func validateAllowedTopologies(topologies []api.TopologySelectorTerm, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if topologies == nil || len(topologies) == 0 {
return allErrs
}
if !utilfeature.DefaultFeatureGate.Enabled(features.DynamicProvisioningScheduling) {
allErrs = append(allErrs, field.Forbidden(fldPath, "field is disabled by feature-gate DynamicProvisioningScheduling"))
}
for i, term := range topologies {
allErrs = append(allErrs, apivalidation.ValidateTopologySelectorTerm(term, fldPath.Index(i))...)
}
return allErrs
}

View File

@ -450,21 +450,22 @@ func TestVolumeAttachmentUpdateValidation(t *testing.T) {
}
}
func makeClassWithBinding(mode *storage.VolumeBindingMode) *storage.StorageClass {
func makeClass(mode *storage.VolumeBindingMode, topologies []api.TopologySelectorTerm) *storage.StorageClass {
return &storage.StorageClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "foo"},
Provisioner: "kubernetes.io/foo-provisioner",
ReclaimPolicy: &deleteReclaimPolicy,
VolumeBindingMode: mode,
AllowedTopologies: topologies,
}
}
// TODO: Remove these tests once feature gate is not required
func TestValidateVolumeBindingModeAlphaDisabled(t *testing.T) {
errorCases := map[string]*storage.StorageClass{
"immediate mode": makeClassWithBinding(&immediateMode1),
"waiting mode": makeClassWithBinding(&waitingMode),
"invalid mode": makeClassWithBinding(&invalidMode),
"immediate mode": makeClass(&immediateMode1, nil),
"waiting mode": makeClass(&waitingMode, nil),
"invalid mode": makeClass(&invalidMode, nil),
}
err := utilfeature.DefaultFeatureGate.Set("VolumeScheduling=false")
@ -486,19 +487,19 @@ type bindingTest struct {
func TestValidateVolumeBindingMode(t *testing.T) {
cases := map[string]bindingTest{
"no mode": {
class: makeClassWithBinding(nil),
class: makeClass(nil, nil),
shouldSucceed: false,
},
"immediate mode": {
class: makeClassWithBinding(&immediateMode1),
class: makeClass(&immediateMode1, nil),
shouldSucceed: true,
},
"waiting mode": {
class: makeClassWithBinding(&waitingMode),
class: makeClass(&waitingMode, nil),
shouldSucceed: true,
},
"invalid mode": {
class: makeClassWithBinding(&invalidMode),
class: makeClass(&invalidMode, nil),
shouldSucceed: false,
},
}
@ -532,10 +533,10 @@ type updateTest struct {
}
func TestValidateUpdateVolumeBindingMode(t *testing.T) {
noBinding := makeClassWithBinding(nil)
immediateBinding1 := makeClassWithBinding(&immediateMode1)
immediateBinding2 := makeClassWithBinding(&immediateMode2)
waitBinding := makeClassWithBinding(&waitingMode)
noBinding := makeClass(nil, nil)
immediateBinding1 := makeClass(&immediateMode1, nil)
immediateBinding2 := makeClass(&immediateMode2, nil)
waitBinding := makeClass(&waitingMode, nil)
cases := map[string]updateTest{
"old and new no mode": {
@ -591,3 +592,102 @@ func TestValidateUpdateVolumeBindingMode(t *testing.T) {
t.Fatalf("Failed to disable feature gate for VolumeScheduling: %v", err)
}
}
func TestValidateAllowedTopologies(t *testing.T) {
validTopology := []api.TopologySelectorTerm{
{
MatchLabelExpressions: []api.TopologySelectorLabelRequirement{
{
Key: "failure-domain.beta.kubernetes.io/zone",
Values: []string{"zone1"},
},
{
Key: "kubernetes.io/hostname",
Values: []string{"node1"},
},
},
},
{
MatchLabelExpressions: []api.TopologySelectorLabelRequirement{
{
Key: "failure-domain.beta.kubernetes.io/zone",
Values: []string{"zone2"},
},
{
Key: "kubernetes.io/hostname",
Values: []string{"node2"},
},
},
},
}
topologyInvalidKey := []api.TopologySelectorTerm{
{
MatchLabelExpressions: []api.TopologySelectorLabelRequirement{
{
Key: "/invalidkey",
Values: []string{"zone1"},
},
},
},
}
topologyLackOfValues := []api.TopologySelectorTerm{
{
MatchLabelExpressions: []api.TopologySelectorLabelRequirement{
{
Key: "kubernetes.io/hostname",
Values: []string{},
},
},
},
}
cases := map[string]bindingTest{
"no topology": {
class: makeClass(nil, nil),
shouldSucceed: true,
},
"valid topology": {
class: makeClass(nil, validTopology),
shouldSucceed: true,
},
"topology invalid key": {
class: makeClass(nil, topologyInvalidKey),
shouldSucceed: false,
},
"topology lack of values": {
class: makeClass(nil, topologyLackOfValues),
shouldSucceed: false,
},
}
// TODO: remove when feature gate not required
err := utilfeature.DefaultFeatureGate.Set("DynamicProvisioningScheduling=true")
if err != nil {
t.Fatalf("Failed to enable feature gate for DynamicProvisioningScheduling: %v", err)
}
for testName, testCase := range cases {
errs := ValidateStorageClass(testCase.class)
if testCase.shouldSucceed && len(errs) != 0 {
t.Errorf("Expected success for test %q, got %v", testName, errs)
}
if !testCase.shouldSucceed && len(errs) == 0 {
t.Errorf("Expected failure for test %q, got success", testName)
}
}
err = utilfeature.DefaultFeatureGate.Set("DynamicProvisioningScheduling=false")
if err != nil {
t.Fatalf("Failed to disable feature gate for DynamicProvisioningScheduling: %v", err)
}
for testName, testCase := range cases {
errs := ValidateStorageClass(testCase.class)
if len(errs) == 0 && testCase.class.AllowedTopologies != nil {
t.Errorf("Expected failure for test %q, got success", testName)
}
}
}

View File

@ -69,6 +69,13 @@ func (in *StorageClass) DeepCopyInto(out *StorageClass) {
**out = **in
}
}
if in.AllowedTopologies != nil {
in, out := &in.AllowedTopologies, &out.AllowedTopologies
*out = make([]core.TopologySelectorTerm, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}

File diff suppressed because it is too large Load Diff

View File

@ -1992,6 +1992,7 @@ message NodeSelectorRequirement {
// A null or empty node selector term matches no objects. The requirements of
// them are ANDed.
// The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
message NodeSelectorTerm {
// A list of node selector requirements by node's labels.
// +optional
@ -4438,6 +4439,28 @@ message Toleration {
optional int64 tolerationSeconds = 5;
}
// A topology selector requirement is a selector that matches given label.
// This is an alpha feature and may change in the future.
message TopologySelectorLabelRequirement {
// The label key that the selector applies to.
optional string key = 1;
// An array of string values. One value must match the label to be selected.
// Each entry in Values is ORed.
repeated string values = 2;
}
// A topology selector term represents the result of label queries.
// A null or empty topology selector term matches no objects.
// The requirements of them are ANDed.
// It provides a subset of functionality as NodeSelectorTerm.
// This is an alpha feature and may change in the future.
message TopologySelectorTerm {
// A list of topology selector requirements by labels.
// +optional
repeated TopologySelectorLabelRequirement matchLabelExpressions = 1;
}
// Volume represents a named volume in a pod that may be accessed by any container in the pod.
message Volume {
// Volume's name.

View File

@ -2389,6 +2389,7 @@ type NodeSelector struct {
// A null or empty node selector term matches no objects. The requirements of
// them are ANDed.
// The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
type NodeSelectorTerm struct {
// A list of node selector requirements by node's labels.
// +optional
@ -2428,6 +2429,27 @@ const (
NodeSelectorOpLt NodeSelectorOperator = "Lt"
)
// A topology selector term represents the result of label queries.
// A null or empty topology selector term matches no objects.
// The requirements of them are ANDed.
// It provides a subset of functionality as NodeSelectorTerm.
// This is an alpha feature and may change in the future.
type TopologySelectorTerm struct {
// A list of topology selector requirements by labels.
// +optional
MatchLabelExpressions []TopologySelectorLabelRequirement `json:"matchLabelExpressions,omitempty" protobuf:"bytes,1,rep,name=matchLabelExpressions"`
}
// A topology selector requirement is a selector that matches given label.
// This is an alpha feature and may change in the future.
type TopologySelectorLabelRequirement struct {
// The label key that the selector applies to.
Key string `json:"key" protobuf:"bytes,1,opt,name=key"`
// An array of string values. One value must match the label to be selected.
// Each entry in Values is ORed.
Values []string `json:"values" protobuf:"bytes,2,rep,name=values"`
}
// Affinity is a group of affinity scheduling rules.
type Affinity struct {
// Describes node affinity scheduling rules for the pod.

View File

@ -1073,7 +1073,7 @@ func (NodeSelectorRequirement) SwaggerDoc() map[string]string {
}
var map_NodeSelectorTerm = map[string]string{
"": "A null or empty node selector term matches no objects. The requirements of them are ANDed.",
"": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.",
"matchExpressions": "A list of node selector requirements by node's labels.",
"matchFields": "A list of node selector requirements by node's fields.",
}
@ -2185,6 +2185,25 @@ func (Toleration) SwaggerDoc() map[string]string {
return map_Toleration
}
var map_TopologySelectorLabelRequirement = map[string]string{
"": "A topology selector requirement is a selector that matches given label. This is an alpha feature and may change in the future.",
"key": "The label key that the selector applies to.",
"values": "An array of string values. One value must match the label to be selected. Each entry in Values is ORed.",
}
func (TopologySelectorLabelRequirement) SwaggerDoc() map[string]string {
return map_TopologySelectorLabelRequirement
}
var map_TopologySelectorTerm = map[string]string{
"": "A topology selector term represents the result of label queries. A null or empty topology selector term matches no objects. The requirements of them are ANDed. It provides a subset of functionality as NodeSelectorTerm. This is an alpha feature and may change in the future.",
"matchLabelExpressions": "A list of topology selector requirements by labels.",
}
func (TopologySelectorTerm) SwaggerDoc() map[string]string {
return map_TopologySelectorTerm
}
var map_Volume = map[string]string{
"": "Volume represents a named volume in a pod that may be accessed by any container in the pod.",
"name": "Volume's name. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",

View File

@ -5588,6 +5588,50 @@ func (in *Toleration) DeepCopy() *Toleration {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TopologySelectorLabelRequirement) DeepCopyInto(out *TopologySelectorLabelRequirement) {
*out = *in
if in.Values != nil {
in, out := &in.Values, &out.Values
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologySelectorLabelRequirement.
func (in *TopologySelectorLabelRequirement) DeepCopy() *TopologySelectorLabelRequirement {
if in == nil {
return nil
}
out := new(TopologySelectorLabelRequirement)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TopologySelectorTerm) DeepCopyInto(out *TopologySelectorTerm) {
*out = *in
if in.MatchLabelExpressions != nil {
in, out := &in.MatchLabelExpressions, &out.MatchLabelExpressions
*out = make([]TopologySelectorLabelRequirement, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologySelectorTerm.
func (in *TopologySelectorTerm) DeepCopy() *TopologySelectorTerm {
if in == nil {
return nil
}
out := new(TopologySelectorTerm)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Volume) DeepCopyInto(out *Volume) {
*out = *in

View File

@ -152,6 +152,18 @@ func (m *StorageClass) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.VolumeBindingMode)))
i += copy(dAtA[i:], *m.VolumeBindingMode)
}
if len(m.AllowedTopologies) > 0 {
for _, msg := range m.AllowedTopologies {
dAtA[i] = 0x42
i++
i = encodeVarintGenerated(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
@ -252,6 +264,12 @@ func (m *StorageClass) Size() (n int) {
l = len(*m.VolumeBindingMode)
n += 1 + l + sovGenerated(uint64(l))
}
if len(m.AllowedTopologies) > 0 {
for _, e := range m.AllowedTopologies {
l = e.Size()
n += 1 + l + sovGenerated(uint64(l))
}
}
return n
}
@ -304,6 +322,7 @@ func (this *StorageClass) String() string {
`MountOptions:` + fmt.Sprintf("%v", this.MountOptions) + `,`,
`AllowVolumeExpansion:` + valueToStringGenerated(this.AllowVolumeExpansion) + `,`,
`VolumeBindingMode:` + valueToStringGenerated(this.VolumeBindingMode) + `,`,
`AllowedTopologies:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.AllowedTopologies), "TopologySelectorTerm", "k8s_io_api_core_v1.TopologySelectorTerm", 1), `&`, ``, 1) + `,`,
`}`,
}, "")
return s
@ -641,6 +660,37 @@ func (m *StorageClass) Unmarshal(dAtA []byte) error {
s := VolumeBindingMode(dAtA[iNdEx:postIndex])
m.VolumeBindingMode = &s
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AllowedTopologies", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.AllowedTopologies = append(m.AllowedTopologies, k8s_io_api_core_v1.TopologySelectorTerm{})
if err := m.AllowedTopologies[len(m.AllowedTopologies)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@ -883,44 +933,48 @@ func init() {
}
var fileDescriptorGenerated = []byte{
// 623 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x4f, 0x6f, 0xd3, 0x3c,
0x18, 0x6f, 0xda, 0xb7, 0x2f, 0x9b, 0xbb, 0x89, 0x2e, 0x0c, 0x29, 0xea, 0x21, 0xa9, 0xc6, 0xa5,
0x9a, 0x84, 0xb3, 0x6e, 0x03, 0x4d, 0x48, 0x20, 0x11, 0x34, 0x09, 0xa4, 0x4d, 0xab, 0x82, 0x34,
0x21, 0xc4, 0x01, 0x37, 0x7d, 0xc8, 0x4c, 0x13, 0x3b, 0xb2, 0x9d, 0x40, 0x6f, 0x7c, 0x04, 0xce,
0x7c, 0x14, 0x3e, 0xc1, 0x8e, 0x3b, 0xee, 0x14, 0xb1, 0xf0, 0x2d, 0x76, 0x42, 0x49, 0xca, 0x9a,
0xad, 0x9d, 0xd8, 0x2d, 0xfe, 0xfd, 0xb3, 0x9f, 0x27, 0x3f, 0xf4, 0x62, 0xbc, 0x27, 0x31, 0xe5,
0xf6, 0x38, 0x1e, 0x82, 0x60, 0xa0, 0x40, 0xda, 0x09, 0xb0, 0x11, 0x17, 0xf6, 0x94, 0x20, 0x11,
0xb5, 0xa5, 0xe2, 0x82, 0xf8, 0x60, 0x27, 0x7d, 0xdb, 0x07, 0x06, 0x82, 0x28, 0x18, 0xe1, 0x48,
0x70, 0xc5, 0xf5, 0x87, 0xa5, 0x0c, 0x93, 0x88, 0xe2, 0xa9, 0x0c, 0x27, 0xfd, 0xce, 0x63, 0x9f,
0xaa, 0x93, 0x78, 0x88, 0x3d, 0x1e, 0xda, 0x3e, 0xf7, 0xb9, 0x5d, 0xa8, 0x87, 0xf1, 0xa7, 0xe2,
0x54, 0x1c, 0x8a, 0xaf, 0x32, 0xa5, 0xb3, 0xb9, 0xf0, 0xb2, 0x21, 0x28, 0x32, 0x77, 0x63, 0x67,
0x77, 0xa6, 0x0d, 0x89, 0x77, 0x42, 0x19, 0x88, 0x89, 0x1d, 0x8d, 0xfd, 0x1c, 0x90, 0x76, 0x08,
0x8a, 0x2c, 0x78, 0x67, 0xc7, 0xbe, 0xcd, 0x25, 0x62, 0xa6, 0x68, 0x08, 0x73, 0x86, 0xa7, 0xff,
0x32, 0x48, 0xef, 0x04, 0x42, 0x32, 0xe7, 0xdb, 0xb9, 0xcd, 0x17, 0x2b, 0x1a, 0xd8, 0x94, 0x29,
0xa9, 0xc4, 0x4d, 0xd3, 0xc6, 0x8f, 0x26, 0x5a, 0x79, 0x5b, 0xce, 0xfd, 0x2a, 0x20, 0x52, 0xea,
0x1f, 0xd1, 0x52, 0x3e, 0xc9, 0x88, 0x28, 0x62, 0x68, 0x5d, 0xad, 0xd7, 0xda, 0xde, 0xc2, 0xb3,
0x4d, 0x5f, 0x05, 0xe3, 0x68, 0xec, 0xe7, 0x80, 0xc4, 0xb9, 0x1a, 0x27, 0x7d, 0x7c, 0x34, 0xfc,
0x0c, 0x9e, 0x3a, 0x04, 0x45, 0x1c, 0xfd, 0x34, 0xb5, 0x6a, 0x59, 0x6a, 0xa1, 0x19, 0xe6, 0x5e,
0xa5, 0xea, 0x4f, 0x50, 0x2b, 0x12, 0x3c, 0xa1, 0x92, 0x72, 0x06, 0xc2, 0xa8, 0x77, 0xb5, 0xde,
0xb2, 0xf3, 0x60, 0x6a, 0x69, 0x0d, 0x66, 0x94, 0x5b, 0xd5, 0xe9, 0x3e, 0x42, 0x11, 0x11, 0x24,
0x04, 0x05, 0x42, 0x1a, 0x8d, 0x6e, 0xa3, 0xd7, 0xda, 0xde, 0xc1, 0x0b, 0x4b, 0x80, 0xab, 0x13,
0xe1, 0xc1, 0x95, 0x6b, 0x9f, 0x29, 0x31, 0x99, 0xbd, 0x6e, 0x46, 0xb8, 0x95, 0x68, 0x7d, 0x8c,
0x56, 0x05, 0x78, 0x01, 0xa1, 0xe1, 0x80, 0x07, 0xd4, 0x9b, 0x18, 0xff, 0x15, 0x2f, 0xdc, 0xcf,
0x52, 0x6b, 0xd5, 0xad, 0x12, 0x97, 0xa9, 0xb5, 0x55, 0xa9, 0x8f, 0xc7, 0x45, 0xde, 0x1d, 0x3c,
0x00, 0x21, 0xa9, 0x54, 0xc0, 0xd4, 0x31, 0x0f, 0xe2, 0x10, 0xae, 0x79, 0xdc, 0xeb, 0xd9, 0xfa,
0x2e, 0x5a, 0x09, 0x79, 0xcc, 0xd4, 0x51, 0xa4, 0x28, 0x67, 0xd2, 0x68, 0x76, 0x1b, 0xbd, 0x65,
0xa7, 0x9d, 0xa5, 0xd6, 0xca, 0x61, 0x05, 0x77, 0xaf, 0xa9, 0xf4, 0x03, 0xb4, 0x4e, 0x82, 0x80,
0x7f, 0x29, 0x2f, 0xd8, 0xff, 0x1a, 0x11, 0x96, 0x6f, 0xc9, 0xf8, 0xbf, 0xab, 0xf5, 0x96, 0x1c,
0x23, 0x4b, 0xad, 0xf5, 0x97, 0x0b, 0x78, 0x77, 0xa1, 0x4b, 0x7f, 0x87, 0xd6, 0x92, 0x02, 0x72,
0x28, 0x1b, 0x51, 0xe6, 0x1f, 0xf2, 0x11, 0x18, 0xf7, 0x8a, 0xa1, 0x37, 0xb3, 0xd4, 0x5a, 0x3b,
0xbe, 0x49, 0x5e, 0x2e, 0x02, 0xdd, 0xf9, 0x90, 0xce, 0x73, 0x74, 0xff, 0xc6, 0xf6, 0xf5, 0x36,
0x6a, 0x8c, 0x61, 0x52, 0x54, 0x6b, 0xd9, 0xcd, 0x3f, 0xf5, 0x75, 0xd4, 0x4c, 0x48, 0x10, 0x43,
0xd9, 0x04, 0xb7, 0x3c, 0x3c, 0xab, 0xef, 0x69, 0x1b, 0x3f, 0x35, 0xd4, 0xae, 0xfe, 0xca, 0x03,
0x2a, 0x95, 0xfe, 0x61, 0xae, 0xa0, 0xf8, 0x6e, 0x05, 0xcd, 0xdd, 0x45, 0x3d, 0xdb, 0xd3, 0x02,
0x2c, 0xfd, 0x45, 0x2a, 0xe5, 0x7c, 0x8d, 0x9a, 0x54, 0x41, 0x28, 0x8d, 0x7a, 0x51, 0xb0, 0x47,
0x77, 0x28, 0x98, 0xb3, 0x3a, 0xcd, 0x6b, 0xbe, 0xc9, 0x9d, 0x6e, 0x19, 0xe0, 0xf4, 0x4e, 0x2f,
0xcc, 0xda, 0xd9, 0x85, 0x59, 0x3b, 0xbf, 0x30, 0x6b, 0xdf, 0x32, 0x53, 0x3b, 0xcd, 0x4c, 0xed,
0x2c, 0x33, 0xb5, 0xf3, 0xcc, 0xd4, 0x7e, 0x65, 0xa6, 0xf6, 0xfd, 0xb7, 0x59, 0x7b, 0x5f, 0x4f,
0xfa, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xee, 0x56, 0xcc, 0xfd, 0x0a, 0x05, 0x00, 0x00,
// 677 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xc1, 0x6e, 0xd3, 0x4a,
0x14, 0x8d, 0x93, 0x97, 0xbe, 0x74, 0xd2, 0xea, 0x25, 0x7e, 0x45, 0x32, 0x59, 0x38, 0x51, 0xd9,
0x44, 0x95, 0x18, 0x37, 0x6d, 0x41, 0x15, 0x12, 0x48, 0x35, 0xaa, 0x04, 0x52, 0xab, 0x46, 0x6e,
0x55, 0x21, 0xc4, 0x82, 0x89, 0x73, 0x71, 0x87, 0xd8, 0x33, 0x66, 0x66, 0x6c, 0xc8, 0x8e, 0x1f,
0x40, 0xe2, 0x7b, 0xf8, 0x82, 0x2e, 0xbb, 0xec, 0x2a, 0xa2, 0xe6, 0x2f, 0xba, 0x42, 0x76, 0x42,
0xe3, 0x26, 0xa9, 0xe8, 0x6e, 0xe6, 0xdc, 0x73, 0xce, 0x9d, 0x3b, 0xf7, 0x5e, 0xf4, 0x62, 0xb0,
0x2b, 0x31, 0xe5, 0xd6, 0x20, 0xea, 0x81, 0x60, 0xa0, 0x40, 0x5a, 0x31, 0xb0, 0x3e, 0x17, 0xd6,
0x24, 0x40, 0x42, 0x6a, 0x49, 0xc5, 0x05, 0xf1, 0xc0, 0x8a, 0x3b, 0x96, 0x07, 0x0c, 0x04, 0x51,
0xd0, 0xc7, 0xa1, 0xe0, 0x8a, 0xeb, 0x0f, 0xc6, 0x34, 0x4c, 0x42, 0x8a, 0x27, 0x34, 0x1c, 0x77,
0x1a, 0x8f, 0x3d, 0xaa, 0xce, 0xa2, 0x1e, 0x76, 0x79, 0x60, 0x79, 0xdc, 0xe3, 0x56, 0xc6, 0xee,
0x45, 0x1f, 0xb2, 0x5b, 0x76, 0xc9, 0x4e, 0x63, 0x97, 0xc6, 0x7a, 0x2e, 0x99, 0xcb, 0xc5, 0xa2,
0x4c, 0x8d, 0x8d, 0x85, 0x0f, 0xea, 0x81, 0x22, 0xf3, 0xdc, 0x9d, 0x29, 0x37, 0x20, 0xee, 0x19,
0x65, 0x20, 0x86, 0x56, 0x38, 0xf0, 0x52, 0x40, 0x5a, 0x01, 0x28, 0xb2, 0x28, 0x83, 0x75, 0x97,
0x4a, 0x44, 0x4c, 0xd1, 0x00, 0xe6, 0x04, 0x4f, 0xff, 0x26, 0x90, 0xee, 0x19, 0x04, 0x64, 0x4e,
0xb7, 0x7d, 0x97, 0x2e, 0x52, 0xd4, 0xb7, 0x28, 0x53, 0x52, 0x89, 0x59, 0xd1, 0xfa, 0xb7, 0x25,
0xb4, 0x72, 0x3c, 0xae, 0xfb, 0xa5, 0x4f, 0xa4, 0xd4, 0xdf, 0xa3, 0x4a, 0x5a, 0x49, 0x9f, 0x28,
0x62, 0x68, 0x2d, 0xad, 0x5d, 0xdd, 0xda, 0xc4, 0xd3, 0x6e, 0xdc, 0x18, 0xe3, 0x70, 0xe0, 0xa5,
0x80, 0xc4, 0x29, 0x1b, 0xc7, 0x1d, 0x7c, 0xd4, 0xfb, 0x08, 0xae, 0x3a, 0x04, 0x45, 0x6c, 0xfd,
0x7c, 0xd4, 0x2c, 0x24, 0xa3, 0x26, 0x9a, 0x62, 0xce, 0x8d, 0xab, 0xfe, 0x04, 0x55, 0x43, 0xc1,
0x63, 0x2a, 0x29, 0x67, 0x20, 0x8c, 0x62, 0x4b, 0x6b, 0x2f, 0xdb, 0xff, 0x4f, 0x24, 0xd5, 0xee,
0x34, 0xe4, 0xe4, 0x79, 0xba, 0x87, 0x50, 0x48, 0x04, 0x09, 0x40, 0x81, 0x90, 0x46, 0xa9, 0x55,
0x6a, 0x57, 0xb7, 0xb6, 0xf1, 0xc2, 0x41, 0xc1, 0xf9, 0x8a, 0x70, 0xf7, 0x46, 0xb5, 0xcf, 0x94,
0x18, 0x4e, 0x5f, 0x37, 0x0d, 0x38, 0x39, 0x6b, 0x7d, 0x80, 0x56, 0x05, 0xb8, 0x3e, 0xa1, 0x41,
0x97, 0xfb, 0xd4, 0x1d, 0x1a, 0xff, 0x64, 0x2f, 0xdc, 0x4f, 0x46, 0xcd, 0x55, 0x27, 0x1f, 0xb8,
0x1e, 0x35, 0x37, 0xe7, 0x47, 0x0c, 0x77, 0x41, 0x48, 0x2a, 0x15, 0x30, 0x75, 0xca, 0xfd, 0x28,
0x80, 0x5b, 0x1a, 0xe7, 0xb6, 0xb7, 0xbe, 0x83, 0x56, 0x02, 0x1e, 0x31, 0x75, 0x14, 0x2a, 0xca,
0x99, 0x34, 0xca, 0xad, 0x52, 0x7b, 0xd9, 0xae, 0x25, 0xa3, 0xe6, 0xca, 0x61, 0x0e, 0x77, 0x6e,
0xb1, 0xf4, 0x03, 0xb4, 0x46, 0x7c, 0x9f, 0x7f, 0x1e, 0x27, 0xd8, 0xff, 0x12, 0x12, 0x96, 0xfe,
0x92, 0xb1, 0xd4, 0xd2, 0xda, 0x15, 0xdb, 0x48, 0x46, 0xcd, 0xb5, 0xbd, 0x05, 0x71, 0x67, 0xa1,
0x4a, 0x7f, 0x83, 0xea, 0x71, 0x06, 0xd9, 0x94, 0xf5, 0x29, 0xf3, 0x0e, 0x79, 0x1f, 0x8c, 0x7f,
0xb3, 0xa2, 0x37, 0x92, 0x51, 0xb3, 0x7e, 0x3a, 0x1b, 0xbc, 0x5e, 0x04, 0x3a, 0xf3, 0x26, 0xfa,
0x27, 0x54, 0xcf, 0x32, 0x42, 0xff, 0x84, 0x87, 0xdc, 0xe7, 0x1e, 0x05, 0x69, 0x54, 0xb2, 0xd6,
0xb5, 0xf3, 0xad, 0x4b, 0xbf, 0x2e, 0xed, 0xdb, 0x84, 0x35, 0x3c, 0x06, 0x1f, 0x5c, 0xc5, 0xc5,
0x09, 0x88, 0xc0, 0x7e, 0x38, 0xe9, 0x57, 0x7d, 0x6f, 0xd6, 0xca, 0x99, 0x77, 0x6f, 0x3c, 0x47,
0xff, 0xcd, 0x34, 0x5c, 0xaf, 0xa1, 0xd2, 0x00, 0x86, 0xd9, 0x34, 0x2f, 0x3b, 0xe9, 0x51, 0x5f,
0x43, 0xe5, 0x98, 0xf8, 0x11, 0x8c, 0x87, 0xcf, 0x19, 0x5f, 0x9e, 0x15, 0x77, 0xb5, 0xf5, 0x1f,
0x1a, 0xaa, 0xe5, 0xa7, 0xe7, 0x80, 0x4a, 0xa5, 0xbf, 0x9b, 0xdb, 0x09, 0x7c, 0xbf, 0x9d, 0x48,
0xd5, 0xd9, 0x46, 0xd4, 0x26, 0x35, 0x54, 0xfe, 0x20, 0xb9, 0x7d, 0x78, 0x85, 0xca, 0x54, 0x41,
0x20, 0x8d, 0x62, 0xf6, 0x31, 0x8f, 0xee, 0x31, 0xd3, 0xf6, 0xea, 0xc4, 0xaf, 0xfc, 0x3a, 0x55,
0x3a, 0x63, 0x03, 0xbb, 0x7d, 0x7e, 0x65, 0x16, 0x2e, 0xae, 0xcc, 0xc2, 0xe5, 0x95, 0x59, 0xf8,
0x9a, 0x98, 0xda, 0x79, 0x62, 0x6a, 0x17, 0x89, 0xa9, 0x5d, 0x26, 0xa6, 0xf6, 0x33, 0x31, 0xb5,
0xef, 0xbf, 0xcc, 0xc2, 0xdb, 0x62, 0xdc, 0xf9, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x0e, 0x67, 0x74,
0x30, 0xa1, 0x05, 0x00, 0x00,
}

View File

@ -21,6 +21,7 @@ syntax = 'proto2';
package k8s.io.api.storage.v1;
import "k8s.io/api/core/v1/generated.proto";
import "k8s.io/api/storage/v1beta1/generated.proto";
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
@ -70,6 +71,14 @@ message StorageClass {
// the VolumeScheduling feature.
// +optional
optional string volumeBindingMode = 7;
// Restrict the node topologies where volumes can be dynamically provisioned.
// Each volume plugin defines its own supported topology specifications.
// An empty TopologySelectorTerm list means there is no topology restriction.
// This field is alpha-level and is only honored by servers that enable
// the DynamicProvisioningScheduling feature.
// +optional
repeated k8s.io.api.core.v1.TopologySelectorTerm allowedTopologies = 8;
}
// StorageClassList is a collection of storage classes.

View File

@ -66,6 +66,14 @@ type StorageClass struct {
// the VolumeScheduling feature.
// +optional
VolumeBindingMode *VolumeBindingMode `json:"volumeBindingMode,omitempty" protobuf:"bytes,7,opt,name=volumeBindingMode"`
// Restrict the node topologies where volumes can be dynamically provisioned.
// Each volume plugin defines its own supported topology specifications.
// An empty TopologySelectorTerm list means there is no topology restriction.
// This field is alpha-level and is only honored by servers that enable
// the DynamicProvisioningScheduling feature.
// +optional
AllowedTopologies []v1.TopologySelectorTerm `json:"allowedTopologies,omitempty" protobuf:"bytes,8,rep,name=allowedTopologies"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -36,6 +36,7 @@ var map_StorageClass = map[string]string{
"mountOptions": "Dynamically provisioned PersistentVolumes of this storage class are created with these mountOptions, e.g. [\"ro\", \"soft\"]. Not validated - mount of the PVs will simply fail if one is invalid.",
"allowVolumeExpansion": "AllowVolumeExpansion shows whether the storage class allow volume expand",
"volumeBindingMode": "VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. When unset, VolumeBindingImmediate is used. This field is alpha-level and is only honored by servers that enable the VolumeScheduling feature.",
"allowedTopologies": "Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature.",
}
func (StorageClass) SwaggerDoc() map[string]string {

View File

@ -69,6 +69,13 @@ func (in *StorageClass) DeepCopyInto(out *StorageClass) {
**out = **in
}
}
if in.AllowedTopologies != nil {
in, out := &in.AllowedTopologies, &out.AllowedTopologies
*out = make([]core_v1.TopologySelectorTerm, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}

View File

@ -188,6 +188,18 @@ func (m *StorageClass) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.VolumeBindingMode)))
i += copy(dAtA[i:], *m.VolumeBindingMode)
}
if len(m.AllowedTopologies) > 0 {
for _, msg := range m.AllowedTopologies {
dAtA[i] = 0x42
i++
i = encodeVarintGenerated(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
@ -524,6 +536,12 @@ func (m *StorageClass) Size() (n int) {
l = len(*m.VolumeBindingMode)
n += 1 + l + sovGenerated(uint64(l))
}
if len(m.AllowedTopologies) > 0 {
for _, e := range m.AllowedTopologies {
l = e.Size()
n += 1 + l + sovGenerated(uint64(l))
}
}
return n
}
@ -657,6 +675,7 @@ func (this *StorageClass) String() string {
`MountOptions:` + fmt.Sprintf("%v", this.MountOptions) + `,`,
`AllowVolumeExpansion:` + valueToStringGenerated(this.AllowVolumeExpansion) + `,`,
`VolumeBindingMode:` + valueToStringGenerated(this.VolumeBindingMode) + `,`,
`AllowedTopologies:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.AllowedTopologies), "TopologySelectorTerm", "k8s_io_api_core_v1.TopologySelectorTerm", 1), `&`, ``, 1) + `,`,
`}`,
}, "")
return s
@ -1073,6 +1092,37 @@ func (m *StorageClass) Unmarshal(dAtA []byte) error {
s := VolumeBindingMode(dAtA[iNdEx:postIndex])
m.VolumeBindingMode = &s
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AllowedTopologies", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.AllowedTopologies = append(m.AllowedTopologies, k8s_io_api_core_v1.TopologySelectorTerm{})
if err := m.AllowedTopologies[len(m.AllowedTopologies)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@ -2145,67 +2195,69 @@ func init() {
}
var fileDescriptorGenerated = []byte{
// 977 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xcd, 0x6f, 0x1b, 0x45,
0x14, 0xcf, 0xc6, 0xf9, 0x1c, 0x27, 0x34, 0x1d, 0x22, 0xb0, 0x7c, 0x58, 0x47, 0xbe, 0x60, 0xaa,
0x66, 0xb7, 0x09, 0x05, 0x45, 0x48, 0x1c, 0xb2, 0x25, 0x07, 0x50, 0xdc, 0x86, 0x29, 0xaa, 0x50,
0xc5, 0x81, 0xc9, 0xee, 0xab, 0x33, 0xd8, 0xfb, 0xa1, 0x99, 0x59, 0xd3, 0xdc, 0x38, 0x71, 0xe6,
0xc4, 0x95, 0x0b, 0xff, 0x07, 0x47, 0x72, 0x42, 0x3d, 0xf6, 0x64, 0x91, 0xe5, 0xbf, 0x88, 0x38,
0xa0, 0x99, 0x9d, 0x78, 0xd7, 0x5e, 0x5b, 0x4d, 0x7a, 0xe8, 0x2d, 0xf3, 0xde, 0xfb, 0xfd, 0xde,
0xd7, 0xef, 0xad, 0x83, 0x1e, 0xf5, 0x0f, 0x84, 0xc3, 0x62, 0xb7, 0x9f, 0x9e, 0x02, 0x8f, 0x40,
0x82, 0x70, 0x87, 0x10, 0x05, 0x31, 0x77, 0x8d, 0x83, 0x26, 0xcc, 0x15, 0x32, 0xe6, 0xb4, 0x07,
0xee, 0x70, 0xef, 0x14, 0x24, 0xdd, 0x73, 0x7b, 0x10, 0x01, 0xa7, 0x12, 0x02, 0x27, 0xe1, 0xb1,
0x8c, 0x71, 0x33, 0x8f, 0x75, 0x68, 0xc2, 0x1c, 0x13, 0xeb, 0x98, 0xd8, 0xe6, 0x6e, 0x8f, 0xc9,
0xb3, 0xf4, 0xd4, 0xf1, 0xe3, 0xd0, 0xed, 0xc5, 0xbd, 0xd8, 0xd5, 0x90, 0xd3, 0xf4, 0x85, 0x7e,
0xe9, 0x87, 0xfe, 0x2b, 0xa7, 0x6a, 0xb6, 0x4b, 0x69, 0xfd, 0x98, 0xab, 0x9c, 0xd3, 0xe9, 0x9a,
0xdd, 0x22, 0x06, 0x5e, 0x4a, 0x88, 0x04, 0x8b, 0x23, 0xb1, 0x4b, 0x13, 0x26, 0x80, 0x0f, 0x81,
0xbb, 0x49, 0xbf, 0xa7, 0x7c, 0x62, 0x32, 0x60, 0x5e, 0xf5, 0xcd, 0x87, 0x05, 0x5d, 0x48, 0xfd,
0x33, 0x16, 0x01, 0x3f, 0x2f, 0x38, 0x42, 0x90, 0x74, 0x56, 0x11, 0xee, 0x3c, 0x14, 0x4f, 0x23,
0xc9, 0x42, 0xa8, 0x00, 0x3e, 0x7b, 0x13, 0x40, 0xf8, 0x67, 0x10, 0xd2, 0x0a, 0xee, 0x93, 0x79,
0xb8, 0x54, 0xb2, 0x81, 0xcb, 0x22, 0x29, 0x24, 0x9f, 0x06, 0xb5, 0x7f, 0x5f, 0x46, 0x1b, 0x4f,
0xf3, 0x4d, 0x3c, 0x1a, 0x50, 0x21, 0xf0, 0x0f, 0x68, 0x4d, 0x75, 0x12, 0x50, 0x49, 0x1b, 0xd6,
0x8e, 0xd5, 0xa9, 0xef, 0x3f, 0x70, 0x8a, 0xad, 0x8d, 0x89, 0x9d, 0xa4, 0xdf, 0x53, 0x06, 0xe1,
0xa8, 0x68, 0x67, 0xb8, 0xe7, 0x3c, 0x39, 0xfd, 0x11, 0x7c, 0xd9, 0x05, 0x49, 0x3d, 0x7c, 0x31,
0x6a, 0x2d, 0x64, 0xa3, 0x16, 0x2a, 0x6c, 0x64, 0xcc, 0x8a, 0x3f, 0x45, 0xf5, 0x84, 0xc7, 0x43,
0xa6, 0x86, 0x0d, 0xbc, 0xb1, 0xb8, 0x63, 0x75, 0xd6, 0xbd, 0xf7, 0x0d, 0xa4, 0x7e, 0x52, 0xb8,
0x48, 0x39, 0x0e, 0x0f, 0x10, 0x4a, 0x28, 0xa7, 0x21, 0x48, 0xe0, 0xa2, 0x51, 0xdb, 0xa9, 0x75,
0xea, 0xfb, 0x07, 0xce, 0x7c, 0x41, 0x39, 0xe5, 0xb6, 0x9c, 0x93, 0x31, 0xf4, 0x28, 0x92, 0xfc,
0xbc, 0x28, 0xb1, 0x70, 0x90, 0x12, 0x3f, 0xee, 0xa3, 0x4d, 0x0e, 0xfe, 0x80, 0xb2, 0xf0, 0x24,
0x1e, 0x30, 0xff, 0xbc, 0xb1, 0xa4, 0xcb, 0x3c, 0xca, 0x46, 0xad, 0x4d, 0x52, 0x76, 0x5c, 0x8d,
0x5a, 0x0f, 0xaa, 0x52, 0x74, 0x4e, 0x80, 0x0b, 0x26, 0x24, 0x44, 0xf2, 0x59, 0x3c, 0x48, 0x43,
0x98, 0xc0, 0x90, 0x49, 0x6e, 0xfc, 0x10, 0x6d, 0x84, 0x71, 0x1a, 0xc9, 0x27, 0x89, 0x54, 0x02,
0x6c, 0x2c, 0xef, 0xd4, 0x3a, 0xeb, 0xde, 0x56, 0x36, 0x6a, 0x6d, 0x74, 0x4b, 0x76, 0x32, 0x11,
0x85, 0x8f, 0xd1, 0x36, 0x1d, 0x0c, 0xe2, 0x9f, 0xf2, 0x04, 0x47, 0x2f, 0x13, 0xaa, 0xf5, 0xdb,
0x58, 0xd9, 0xb1, 0x3a, 0x6b, 0x5e, 0x23, 0x1b, 0xb5, 0xb6, 0x0f, 0x67, 0xf8, 0xc9, 0x4c, 0x14,
0xfe, 0x0e, 0xdd, 0x1d, 0x6a, 0x93, 0xc7, 0xa2, 0x80, 0x45, 0xbd, 0x6e, 0x1c, 0x40, 0x63, 0x55,
0x37, 0x7d, 0x2f, 0x1b, 0xb5, 0xee, 0x3e, 0x9b, 0x76, 0x5e, 0xcd, 0x32, 0x92, 0x2a, 0x49, 0xf3,
0x0b, 0x74, 0x67, 0x6a, 0xfa, 0x78, 0x0b, 0xd5, 0xfa, 0x70, 0xae, 0xf5, 0xb5, 0x4e, 0xd4, 0x9f,
0x78, 0x1b, 0x2d, 0x0f, 0xe9, 0x20, 0x85, 0x5c, 0x0e, 0x24, 0x7f, 0x7c, 0xbe, 0x78, 0x60, 0xb5,
0xff, 0xb4, 0xd0, 0x56, 0x79, 0x95, 0xc7, 0x4c, 0x48, 0xfc, 0x7d, 0x45, 0xa5, 0xce, 0xcd, 0x54,
0xaa, 0xd0, 0x5a, 0xa3, 0x5b, 0x46, 0x00, 0x6b, 0xd7, 0x96, 0x92, 0x42, 0xbb, 0x68, 0x99, 0x49,
0x08, 0x45, 0x63, 0x51, 0xab, 0xac, 0x73, 0x53, 0x95, 0x79, 0x9b, 0x86, 0x74, 0xf9, 0x2b, 0x05,
0x27, 0x39, 0x4b, 0xfb, 0x8f, 0x45, 0xb4, 0x95, 0x4f, 0xea, 0x50, 0x4a, 0xea, 0x9f, 0x85, 0x10,
0xc9, 0x77, 0x70, 0x67, 0x04, 0x2d, 0x89, 0x04, 0x7c, 0x3d, 0xd1, 0x49, 0xf6, 0x4a, 0x13, 0xd3,
0xd5, 0x3d, 0x4d, 0xc0, 0xf7, 0x36, 0x0c, 0xfb, 0x92, 0x7a, 0x11, 0xcd, 0x85, 0x9f, 0xa3, 0x15,
0x21, 0xa9, 0x4c, 0xd5, 0x01, 0x2a, 0xd6, 0xfd, 0x5b, 0xb1, 0x6a, 0xa4, 0xf7, 0x9e, 0xe1, 0x5d,
0xc9, 0xdf, 0xc4, 0x30, 0xb6, 0xff, 0xb2, 0xd0, 0xf6, 0x34, 0xe4, 0x1d, 0x2c, 0xfb, 0x9b, 0xc9,
0x65, 0xdf, 0xbf, 0x4d, 0x47, 0x73, 0x16, 0xfe, 0x02, 0x7d, 0x50, 0xe9, 0x3d, 0x4e, 0xb9, 0x0f,
0xea, 0x66, 0x93, 0xa9, 0x2f, 0xc3, 0x63, 0x1a, 0x42, 0x7e, 0x09, 0xf9, 0xcd, 0x9e, 0xcc, 0xf0,
0x93, 0x99, 0xa8, 0xf6, 0xdf, 0x33, 0x26, 0xa6, 0x96, 0x85, 0xef, 0xa3, 0x35, 0xaa, 0x2d, 0xc0,
0x0d, 0xf5, 0x78, 0x02, 0x87, 0xc6, 0x4e, 0xc6, 0x11, 0x7a, 0xa9, 0xba, 0x3c, 0x23, 0x95, 0xdb,
0x2d, 0x55, 0x23, 0x4b, 0x4b, 0xd5, 0x6f, 0x62, 0x18, 0x55, 0x25, 0x51, 0x1c, 0xe4, 0x4d, 0xd6,
0x26, 0x2b, 0x79, 0x6c, 0xec, 0x64, 0x1c, 0xd1, 0xfe, 0xaf, 0x36, 0x63, 0x72, 0x5a, 0x1d, 0xa5,
0x96, 0x02, 0xdd, 0xd2, 0x5a, 0xa5, 0xa5, 0x60, 0xdc, 0x52, 0x80, 0x7f, 0xb3, 0x10, 0xa6, 0x63,
0x8a, 0xee, 0xb5, 0x7a, 0xf2, 0x15, 0x7f, 0x7d, 0x7b, 0xd1, 0x3a, 0x87, 0x15, 0xb2, 0xfc, 0x77,
0xa4, 0x69, 0x8a, 0xc0, 0xd5, 0x00, 0x32, 0xa3, 0x02, 0xcc, 0x50, 0x3d, 0xb7, 0x1e, 0x71, 0x1e,
0x73, 0x73, 0x45, 0x1f, 0xbd, 0xb9, 0x20, 0x1d, 0xee, 0xd9, 0xea, 0x17, 0xf2, 0xb0, 0xc0, 0x5f,
0x8d, 0x5a, 0xf5, 0x92, 0x9f, 0x94, 0xb9, 0x55, 0xaa, 0x00, 0x8a, 0x54, 0x4b, 0x6f, 0x91, 0xea,
0x4b, 0x98, 0x9f, 0xaa, 0xc4, 0xdd, 0x3c, 0x42, 0x1f, 0xce, 0x19, 0xd0, 0xad, 0x3e, 0xf5, 0xbf,
0x58, 0xa8, 0x9c, 0x03, 0x1f, 0xa3, 0x25, 0xf5, 0x0f, 0x8f, 0x39, 0xfa, 0x7b, 0x37, 0x3b, 0xfa,
0x6f, 0x59, 0x08, 0xc5, 0xb7, 0x4b, 0xbd, 0x88, 0x66, 0xc1, 0x1f, 0xa3, 0xd5, 0x10, 0x84, 0xa0,
0x3d, 0x93, 0xd9, 0xbb, 0x63, 0x82, 0x56, 0xbb, 0xb9, 0x99, 0x5c, 0xfb, 0xbd, 0xdd, 0x8b, 0x4b,
0x7b, 0xe1, 0xd5, 0xa5, 0xbd, 0xf0, 0xfa, 0xd2, 0x5e, 0xf8, 0x39, 0xb3, 0xad, 0x8b, 0xcc, 0xb6,
0x5e, 0x65, 0xb6, 0xf5, 0x3a, 0xb3, 0xad, 0x7f, 0x32, 0xdb, 0xfa, 0xf5, 0x5f, 0x7b, 0xe1, 0xf9,
0xaa, 0x99, 0xdb, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x4b, 0x7f, 0x8a, 0x3b, 0x1c, 0x0b, 0x00,
0x00,
// 1022 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4d, 0x6f, 0x1b, 0x45,
0x18, 0xce, 0xc6, 0xf9, 0x70, 0xc6, 0x09, 0x4d, 0x96, 0x08, 0x8c, 0x0f, 0x76, 0xe4, 0x0b, 0xa6,
0x6a, 0x76, 0x9b, 0x50, 0x50, 0x84, 0xc4, 0xc1, 0x5b, 0x72, 0x00, 0xc5, 0x6d, 0x98, 0x44, 0x15,
0xaa, 0x38, 0x30, 0xd9, 0x7d, 0xeb, 0x0c, 0xde, 0xdd, 0x59, 0x66, 0xc6, 0xa6, 0xb9, 0x71, 0xe2,
0x8c, 0x38, 0xf0, 0x0b, 0xf8, 0x1f, 0x1c, 0xc9, 0x09, 0xf5, 0xd8, 0x93, 0x45, 0xcc, 0xbf, 0x88,
0x38, 0xa0, 0x99, 0x9d, 0x78, 0xd7, 0x5e, 0x9b, 0x36, 0x3d, 0xf4, 0xe6, 0xf7, 0xe3, 0x79, 0xde,
0xef, 0x59, 0xa3, 0x87, 0xbd, 0x03, 0xe1, 0x50, 0xe6, 0xf6, 0xfa, 0x67, 0xc0, 0x63, 0x90, 0x20,
0xdc, 0x01, 0xc4, 0x01, 0xe3, 0xae, 0x31, 0x90, 0x84, 0xba, 0x42, 0x32, 0x4e, 0xba, 0xe0, 0x0e,
0xf6, 0xce, 0x40, 0x92, 0x3d, 0xb7, 0x0b, 0x31, 0x70, 0x22, 0x21, 0x70, 0x12, 0xce, 0x24, 0xb3,
0x6b, 0xa9, 0xaf, 0x43, 0x12, 0xea, 0x18, 0x5f, 0xc7, 0xf8, 0xd6, 0x76, 0xbb, 0x54, 0x9e, 0xf7,
0xcf, 0x1c, 0x9f, 0x45, 0x6e, 0x97, 0x75, 0x99, 0xab, 0x21, 0x67, 0xfd, 0x67, 0x5a, 0xd2, 0x82,
0xfe, 0x95, 0x52, 0xd5, 0x9a, 0xb9, 0xb0, 0x3e, 0xe3, 0x2a, 0xe6, 0x74, 0xb8, 0x5a, 0x27, 0xf3,
0x81, 0xe7, 0x12, 0x62, 0x41, 0x59, 0x2c, 0x76, 0x49, 0x42, 0x05, 0xf0, 0x01, 0x70, 0x37, 0xe9,
0x75, 0x95, 0x4d, 0x4c, 0x3a, 0xcc, 0xcb, 0xbe, 0xf6, 0x20, 0xa3, 0x8b, 0x88, 0x7f, 0x4e, 0x63,
0xe0, 0x17, 0x19, 0x47, 0x04, 0x92, 0xcc, 0x4a, 0xc2, 0x9d, 0x87, 0xe2, 0xfd, 0x58, 0xd2, 0x08,
0x0a, 0x80, 0x4f, 0x5f, 0x05, 0x10, 0xfe, 0x39, 0x44, 0xa4, 0x80, 0xfb, 0x78, 0x1e, 0xae, 0x2f,
0x69, 0xe8, 0xd2, 0x58, 0x0a, 0xc9, 0xa7, 0x41, 0xcd, 0x5f, 0x57, 0xd0, 0xfa, 0x49, 0x3a, 0x89,
0x87, 0x21, 0x11, 0xc2, 0xfe, 0x0e, 0x95, 0x55, 0x25, 0x01, 0x91, 0xa4, 0x6a, 0xed, 0x58, 0xad,
0xca, 0xfe, 0x7d, 0x27, 0x9b, 0xda, 0x98, 0xd8, 0x49, 0x7a, 0x5d, 0xa5, 0x10, 0x8e, 0xf2, 0x76,
0x06, 0x7b, 0xce, 0xe3, 0xb3, 0xef, 0xc1, 0x97, 0x1d, 0x90, 0xc4, 0xb3, 0x2f, 0x87, 0x8d, 0x85,
0xd1, 0xb0, 0x81, 0x32, 0x1d, 0x1e, 0xb3, 0xda, 0x9f, 0xa0, 0x4a, 0xc2, 0xd9, 0x80, 0xaa, 0x66,
0x03, 0xaf, 0x2e, 0xee, 0x58, 0xad, 0x35, 0xef, 0x5d, 0x03, 0xa9, 0x1c, 0x67, 0x26, 0x9c, 0xf7,
0xb3, 0x43, 0x84, 0x12, 0xc2, 0x49, 0x04, 0x12, 0xb8, 0xa8, 0x96, 0x76, 0x4a, 0xad, 0xca, 0xfe,
0x81, 0x33, 0x7f, 0xa1, 0x9c, 0x7c, 0x59, 0xce, 0xf1, 0x18, 0x7a, 0x18, 0x4b, 0x7e, 0x91, 0xa5,
0x98, 0x19, 0x70, 0x8e, 0xdf, 0xee, 0xa1, 0x0d, 0x0e, 0x7e, 0x48, 0x68, 0x74, 0xcc, 0x42, 0xea,
0x5f, 0x54, 0x97, 0x74, 0x9a, 0x87, 0xa3, 0x61, 0x63, 0x03, 0xe7, 0x0d, 0xd7, 0xc3, 0xc6, 0xfd,
0xe2, 0x2a, 0x3a, 0xc7, 0xc0, 0x05, 0x15, 0x12, 0x62, 0xf9, 0x84, 0x85, 0xfd, 0x08, 0x26, 0x30,
0x78, 0x92, 0xdb, 0x7e, 0x80, 0xd6, 0x23, 0xd6, 0x8f, 0xe5, 0xe3, 0x44, 0xaa, 0x05, 0xac, 0x2e,
0xef, 0x94, 0x5a, 0x6b, 0xde, 0xe6, 0x68, 0xd8, 0x58, 0xef, 0xe4, 0xf4, 0x78, 0xc2, 0xcb, 0x3e,
0x42, 0xdb, 0x24, 0x0c, 0xd9, 0x8f, 0x69, 0x80, 0xc3, 0xe7, 0x09, 0xd1, 0xfb, 0x5b, 0x5d, 0xd9,
0xb1, 0x5a, 0x65, 0xaf, 0x3a, 0x1a, 0x36, 0xb6, 0xdb, 0x33, 0xec, 0x78, 0x26, 0xca, 0xfe, 0x06,
0x6d, 0x0d, 0xb4, 0xca, 0xa3, 0x71, 0x40, 0xe3, 0x6e, 0x87, 0x05, 0x50, 0x5d, 0xd5, 0x45, 0xdf,
0x1d, 0x0d, 0x1b, 0x5b, 0x4f, 0xa6, 0x8d, 0xd7, 0xb3, 0x94, 0xb8, 0x48, 0x62, 0xff, 0x80, 0xb6,
0x74, 0x44, 0x08, 0x4e, 0x59, 0xc2, 0x42, 0xd6, 0xa5, 0x20, 0xaa, 0x65, 0x3d, 0xbf, 0x56, 0x7e,
0x7e, 0xaa, 0x75, 0x6a, 0x91, 0x8c, 0xd7, 0xc5, 0x09, 0x84, 0xe0, 0x4b, 0xc6, 0x4f, 0x81, 0x47,
0xde, 0x07, 0x66, 0x5e, 0x5b, 0xed, 0x69, 0x2a, 0x5c, 0x64, 0xaf, 0x7d, 0x8e, 0xee, 0x4c, 0x0d,
0xdc, 0xde, 0x44, 0xa5, 0x1e, 0x5c, 0xe8, 0x95, 0x5e, 0xc3, 0xea, 0xa7, 0xbd, 0x8d, 0x96, 0x07,
0x24, 0xec, 0x43, 0xba, 0x81, 0x38, 0x15, 0x3e, 0x5b, 0x3c, 0xb0, 0x9a, 0x7f, 0x58, 0x68, 0x33,
0xbf, 0x3d, 0x47, 0x54, 0x48, 0xfb, 0xdb, 0xc2, 0x61, 0x38, 0xaf, 0x77, 0x18, 0x0a, 0xad, 0xcf,
0x62, 0xd3, 0xd4, 0x50, 0xbe, 0xd1, 0xe4, 0x8e, 0xa2, 0x83, 0x96, 0xa9, 0x84, 0x48, 0x54, 0x17,
0x8b, 0x8d, 0xf9, 0xbf, 0xc5, 0xf6, 0x36, 0x0c, 0xe9, 0xf2, 0x97, 0x0a, 0x8e, 0x53, 0x96, 0xe6,
0xef, 0x8b, 0x68, 0x33, 0x1d, 0x4e, 0x5b, 0x4a, 0xe2, 0x9f, 0x47, 0x10, 0xcb, 0xb7, 0x70, 0xda,
0x18, 0x2d, 0x89, 0x04, 0x7c, 0xdd, 0xd1, 0x49, 0xf6, 0x42, 0x11, 0xd3, 0xd9, 0x9d, 0x24, 0xe0,
0x7b, 0xeb, 0x86, 0x7d, 0x49, 0x49, 0x58, 0x73, 0xd9, 0x4f, 0xd1, 0x8a, 0x90, 0x44, 0xf6, 0xd5,
0xcd, 0x2b, 0xd6, 0xfd, 0x5b, 0xb1, 0x6a, 0xa4, 0xf7, 0x8e, 0xe1, 0x5d, 0x49, 0x65, 0x6c, 0x18,
0x9b, 0x7f, 0x5a, 0x68, 0x7b, 0x1a, 0xf2, 0x16, 0x86, 0xfd, 0xf5, 0xe4, 0xb0, 0xef, 0xdd, 0xa6,
0xa2, 0x39, 0x03, 0x7f, 0x86, 0xde, 0x2b, 0xd4, 0xce, 0xfa, 0xdc, 0x07, 0xf5, 0x4c, 0x24, 0x53,
0x8f, 0xd1, 0x23, 0x12, 0x41, 0x7a, 0x09, 0xe9, 0x33, 0x71, 0x3c, 0xc3, 0x8e, 0x67, 0xa2, 0x9a,
0x7f, 0xcd, 0xe8, 0x98, 0x1a, 0x96, 0x7d, 0x0f, 0x95, 0x89, 0xd6, 0x00, 0x37, 0xd4, 0xe3, 0x0e,
0xb4, 0x8d, 0x1e, 0x8f, 0x3d, 0xf4, 0x50, 0x75, 0x7a, 0x66, 0x55, 0x6e, 0x37, 0x54, 0x8d, 0xcc,
0x0d, 0x55, 0xcb, 0xd8, 0x30, 0xaa, 0x4c, 0x62, 0x16, 0xa4, 0x45, 0x96, 0x26, 0x33, 0x79, 0x64,
0xf4, 0x78, 0xec, 0xd1, 0xfc, 0xb7, 0x34, 0xa3, 0x73, 0x7a, 0x3b, 0x72, 0x25, 0x05, 0xba, 0xa4,
0x72, 0xa1, 0xa4, 0x60, 0x5c, 0x52, 0x60, 0xff, 0x66, 0x21, 0x9b, 0x8c, 0x29, 0x3a, 0x37, 0xdb,
0x93, 0x8e, 0xf8, 0xab, 0xdb, 0x2f, 0xad, 0xd3, 0x2e, 0x90, 0xa5, 0x9f, 0xae, 0x9a, 0x49, 0xc2,
0x2e, 0x3a, 0xe0, 0x19, 0x19, 0xd8, 0x14, 0x55, 0x52, 0xed, 0x21, 0xe7, 0x8c, 0x9b, 0x2b, 0xfa,
0xf0, 0xd5, 0x09, 0x69, 0x77, 0xaf, 0xae, 0x3e, 0xca, 0xed, 0x0c, 0x7f, 0x3d, 0x6c, 0x54, 0x72,
0x76, 0x9c, 0xe7, 0x56, 0xa1, 0x02, 0xc8, 0x42, 0x2d, 0xbd, 0x41, 0xa8, 0x2f, 0x60, 0x7e, 0xa8,
0x1c, 0x77, 0xed, 0x10, 0xbd, 0x3f, 0xa7, 0x41, 0xb7, 0x7a, 0xea, 0x7f, 0xb6, 0x50, 0x3e, 0x86,
0x7d, 0x84, 0x96, 0xd4, 0x7f, 0x2c, 0x73, 0xf4, 0x77, 0x5f, 0xef, 0xe8, 0x4f, 0x69, 0x04, 0xd9,
0xdb, 0xa5, 0x24, 0xac, 0x59, 0xec, 0x8f, 0xd0, 0x6a, 0x04, 0x42, 0x90, 0xae, 0x89, 0xec, 0xdd,
0x31, 0x4e, 0xab, 0x9d, 0x54, 0x8d, 0x6f, 0xec, 0xde, 0xee, 0xe5, 0x55, 0x7d, 0xe1, 0xc5, 0x55,
0x7d, 0xe1, 0xe5, 0x55, 0x7d, 0xe1, 0xa7, 0x51, 0xdd, 0xba, 0x1c, 0xd5, 0xad, 0x17, 0xa3, 0xba,
0xf5, 0x72, 0x54, 0xb7, 0xfe, 0x1e, 0xd5, 0xad, 0x5f, 0xfe, 0xa9, 0x2f, 0x3c, 0x5d, 0x35, 0x7d,
0xfb, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xd8, 0xa9, 0x81, 0xd5, 0x8f, 0x0b, 0x00, 0x00,
}

View File

@ -71,6 +71,14 @@ message StorageClass {
// the VolumeScheduling feature.
// +optional
optional string volumeBindingMode = 7;
// Restrict the node topologies where volumes can be dynamically provisioned.
// Each volume plugin defines its own supported topology specifications.
// An empty TopologySelectorTerm list means there is no topology restriction.
// This field is alpha-level and is only honored by servers that enable
// the DynamicProvisioningScheduling feature.
// +optional
repeated k8s.io.api.core.v1.TopologySelectorTerm allowedTopologies = 8;
}
// StorageClassList is a collection of storage classes.

View File

@ -66,6 +66,14 @@ type StorageClass struct {
// the VolumeScheduling feature.
// +optional
VolumeBindingMode *VolumeBindingMode `json:"volumeBindingMode,omitempty" protobuf:"bytes,7,opt,name=volumeBindingMode"`
// Restrict the node topologies where volumes can be dynamically provisioned.
// Each volume plugin defines its own supported topology specifications.
// An empty TopologySelectorTerm list means there is no topology restriction.
// This field is alpha-level and is only honored by servers that enable
// the DynamicProvisioningScheduling feature.
// +optional
AllowedTopologies []v1.TopologySelectorTerm `json:"allowedTopologies,omitempty" protobuf:"bytes,8,rep,name=allowedTopologies"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -36,6 +36,7 @@ var map_StorageClass = map[string]string{
"mountOptions": "Dynamically provisioned PersistentVolumes of this storage class are created with these mountOptions, e.g. [\"ro\", \"soft\"]. Not validated - mount of the PVs will simply fail if one is invalid.",
"allowVolumeExpansion": "AllowVolumeExpansion shows whether the storage class allow volume expand",
"volumeBindingMode": "VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. When unset, VolumeBindingImmediate is used. This field is alpha-level and is only honored by servers that enable the VolumeScheduling feature.",
"allowedTopologies": "Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature.",
}
func (StorageClass) SwaggerDoc() map[string]string {

View File

@ -69,6 +69,13 @@ func (in *StorageClass) DeepCopyInto(out *StorageClass) {
**out = **in
}
}
if in.AllowedTopologies != nil {
in, out := &in.AllowedTopologies, &out.AllowedTopologies
*out = make([]v1.TopologySelectorTerm, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}