Commit 83c78fdc authored by k8s-merge-robot's avatar k8s-merge-robot

Merge pull request #24179 from…

Merge pull request #24179 from aveshagarwal/master-downward-api-resources-limits-requests-implementation Automatic merge from submit-queue Downward API implementation for resources limits and requests This is an implementation of Downward API for resources limits and requests, and it works with environment variables and volume plugin. This is based on proposal https://github.com/kubernetes/kubernetes/pull/24051. This implementation follows API with magic keys approach as discussed in the proposal. @kubernetes/rh-cluster-infra <!-- Reviewable:start --> --- This change is [<img src="http://reviewable.k8s.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](http://reviewable.k8s.io/reviews/kubernetes/kubernetes/24179) <!-- Reviewable:end -->
parents dec18dab 19319314
......@@ -1709,8 +1709,7 @@
"id": "v1.DownwardAPIVolumeFile",
"description": "DownwardAPIVolumeFile represents information to create the file containing the pod field",
"required": [
"path",
"fieldRef"
"path"
],
"properties": {
"path": {
......@@ -1720,6 +1719,10 @@
"fieldRef": {
"$ref": "v1.ObjectFieldSelector",
"description": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported."
},
"resourceFieldRef": {
"$ref": "v1.ResourceFieldSelector",
"description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported."
}
}
},
......@@ -1740,6 +1743,27 @@
}
}
},
"v1.ResourceFieldSelector": {
"id": "v1.ResourceFieldSelector",
"description": "ResourceFieldSelector represents container resources (cpu, memory) and their output format",
"required": [
"resource"
],
"properties": {
"containerName": {
"type": "string",
"description": "Container name: required for volumes, optional for env vars"
},
"resource": {
"type": "string",
"description": "Required: resource to select"
},
"divisor": {
"type": "string",
"description": "Specifies the output format of the exposed resources, defaults to \"1\""
}
}
},
"v1.FCVolumeSource": {
"id": "v1.FCVolumeSource",
"description": "Represents a Fibre Channel volume. Fibre Channel volumes can only be mounted as read/write once. Fibre Channel volumes support ownership management and SELinux relabeling.",
......@@ -1982,6 +2006,10 @@
"$ref": "v1.ObjectFieldSelector",
"description": "Selects a field of the pod; only name and namespace are supported."
},
"resourceFieldRef": {
"$ref": "v1.ResourceFieldSelector",
"description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported."
},
"configMapKeyRef": {
"$ref": "v1.ConfigMapKeySelector",
"description": "Selects a key of a ConfigMap."
......
......@@ -1714,8 +1714,7 @@
"id": "v1.DownwardAPIVolumeFile",
"description": "DownwardAPIVolumeFile represents information to create the file containing the pod field",
"required": [
"path",
"fieldRef"
"path"
],
"properties": {
"path": {
......@@ -1725,6 +1724,10 @@
"fieldRef": {
"$ref": "v1.ObjectFieldSelector",
"description": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported."
},
"resourceFieldRef": {
"$ref": "v1.ResourceFieldSelector",
"description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported."
}
}
},
......@@ -1745,6 +1748,27 @@
}
}
},
"v1.ResourceFieldSelector": {
"id": "v1.ResourceFieldSelector",
"description": "ResourceFieldSelector represents container resources (cpu, memory) and their output format",
"required": [
"resource"
],
"properties": {
"containerName": {
"type": "string",
"description": "Container name: required for volumes, optional for env vars"
},
"resource": {
"type": "string",
"description": "Required: resource to select"
},
"divisor": {
"type": "string",
"description": "Specifies the output format of the exposed resources, defaults to \"1\""
}
}
},
"v1.FCVolumeSource": {
"id": "v1.FCVolumeSource",
"description": "Represents a Fibre Channel volume. Fibre Channel volumes can only be mounted as read/write once. Fibre Channel volumes support ownership management and SELinux relabeling.",
......@@ -1987,6 +2011,10 @@
"$ref": "v1.ObjectFieldSelector",
"description": "Selects a field of the pod; only name and namespace are supported."
},
"resourceFieldRef": {
"$ref": "v1.ResourceFieldSelector",
"description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported."
},
"configMapKeyRef": {
"$ref": "v1.ConfigMapKeySelector",
"description": "Selects a key of a ConfigMap."
......
......@@ -7021,8 +7021,7 @@
"id": "v1.DownwardAPIVolumeFile",
"description": "DownwardAPIVolumeFile represents information to create the file containing the pod field",
"required": [
"path",
"fieldRef"
"path"
],
"properties": {
"path": {
......@@ -7032,6 +7031,10 @@
"fieldRef": {
"$ref": "v1.ObjectFieldSelector",
"description": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported."
},
"resourceFieldRef": {
"$ref": "v1.ResourceFieldSelector",
"description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported."
}
}
},
......@@ -7052,6 +7055,27 @@
}
}
},
"v1.ResourceFieldSelector": {
"id": "v1.ResourceFieldSelector",
"description": "ResourceFieldSelector represents container resources (cpu, memory) and their output format",
"required": [
"resource"
],
"properties": {
"containerName": {
"type": "string",
"description": "Container name: required for volumes, optional for env vars"
},
"resource": {
"type": "string",
"description": "Required: resource to select"
},
"divisor": {
"type": "string",
"description": "Specifies the output format of the exposed resources, defaults to \"1\""
}
}
},
"v1.FCVolumeSource": {
"id": "v1.FCVolumeSource",
"description": "Represents a Fibre Channel volume. Fibre Channel volumes can only be mounted as read/write once. Fibre Channel volumes support ownership management and SELinux relabeling.",
......@@ -7294,6 +7318,10 @@
"$ref": "v1.ObjectFieldSelector",
"description": "Selects a field of the pod; only name and namespace are supported."
},
"resourceFieldRef": {
"$ref": "v1.ResourceFieldSelector",
"description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported."
},
"configMapKeyRef": {
"$ref": "v1.ConfigMapKeySelector",
"description": "Selects a key of a ConfigMap."
......
......@@ -17105,8 +17105,7 @@
"id": "v1.DownwardAPIVolumeFile",
"description": "DownwardAPIVolumeFile represents information to create the file containing the pod field",
"required": [
"path",
"fieldRef"
"path"
],
"properties": {
"path": {
......@@ -17116,6 +17115,10 @@
"fieldRef": {
"$ref": "v1.ObjectFieldSelector",
"description": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported."
},
"resourceFieldRef": {
"$ref": "v1.ResourceFieldSelector",
"description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported."
}
}
},
......@@ -17136,6 +17139,27 @@
}
}
},
"v1.ResourceFieldSelector": {
"id": "v1.ResourceFieldSelector",
"description": "ResourceFieldSelector represents container resources (cpu, memory) and their output format",
"required": [
"resource"
],
"properties": {
"containerName": {
"type": "string",
"description": "Container name: required for volumes, optional for env vars"
},
"resource": {
"type": "string",
"description": "Required: resource to select"
},
"divisor": {
"type": "string",
"description": "Specifies the output format of the exposed resources, defaults to \"1\""
}
}
},
"v1.ConfigMapVolumeSource": {
"id": "v1.ConfigMapVolumeSource",
"description": "Adapts a ConfigMap into a volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. ConfigMap volumes support ownership management and SELinux relabeling.",
......@@ -17309,6 +17333,10 @@
"$ref": "v1.ObjectFieldSelector",
"description": "Selects a field of the pod; only name and namespace are supported."
},
"resourceFieldRef": {
"$ref": "v1.ResourceFieldSelector",
"description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported."
},
"configMapKeyRef": {
"$ref": "v1.ConfigMapKeySelector",
"description": "Selects a key of a ConfigMap."
......
......@@ -2754,6 +2754,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">resourceFieldRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.</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_resourcefieldselector">v1.ResourceFieldSelector</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">configMapKeyRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Selects a key of a ConfigMap.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
......@@ -3200,6 +3207,54 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</div>
<div class="sect2">
<h3 id="_v1_resourcefieldselector">v1.ResourceFieldSelector</h3>
<div class="paragraph">
<p>ResourceFieldSelector represents container resources (cpu, memory) and their output format</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">containerName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Container name: required for volumes, optional for env vars</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">resource</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Required: resource to select</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">divisor</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Specifies the output format of the exposed resources, defaults to "1"</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="_v1_probe">v1.Probe</h3>
<div class="paragraph">
<p>Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic.</p>
......@@ -3546,10 +3601,17 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">fieldRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.</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">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_objectfieldselector">v1.ObjectFieldSelector</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">resourceFieldRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.</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_resourcefieldselector">v1.ResourceFieldSelector</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
......@@ -4034,7 +4096,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</div>
<div id="footer">
<div id="footer-text">
Last updated 2016-05-21 03:08:23 UTC
Last updated 2016-05-24 11:53:33 UTC
</div>
</div>
</body>
......
......@@ -1344,47 +1344,6 @@ Examples:<br>
</div>
<div class="sect2">
<h3 id="_v1_capabilities">v1.Capabilities</h3>
<div class="paragraph">
<p>Adds and removes POSIX capabilities from running containers.</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">add</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Added capabilities</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_capability">v1.Capability</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">drop</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Removed capabilities</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_capability">v1.Capability</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1beta1_jobstatus">v1beta1.JobStatus</h3>
<div class="paragraph">
<p>JobStatus represents the current state of a Job.</p>
......@@ -1454,6 +1413,47 @@ Examples:<br>
</div>
<div class="sect2">
<h3 id="_v1_capabilities">v1.Capabilities</h3>
<div class="paragraph">
<p>Adds and removes POSIX capabilities from running containers.</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">add</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Added capabilities</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_capability">v1.Capability</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">drop</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Removed capabilities</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_capability">v1.Capability</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_localobjectreference">v1.LocalObjectReference</h3>
<div class="paragraph">
<p>LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.</p>
......@@ -2345,6 +2345,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">resourceFieldRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.</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_resourcefieldselector">v1.ResourceFieldSelector</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">configMapKeyRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Selects a key of a ConfigMap.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
......@@ -2942,6 +2949,54 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</div>
<div class="sect2">
<h3 id="_v1_resourcefieldselector">v1.ResourceFieldSelector</h3>
<div class="paragraph">
<p>ResourceFieldSelector represents container resources (cpu, memory) and their output format</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">containerName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Container name: required for volumes, optional for env vars</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">resource</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Required: resource to select</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">divisor</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Specifies the output format of the exposed resources, defaults to "1"</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="_v1_probe">v1.Probe</h3>
<div class="paragraph">
<p>Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic.</p>
......@@ -3288,10 +3343,17 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">fieldRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.</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">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_objectfieldselector">v1.ObjectFieldSelector</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">resourceFieldRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.</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_resourcefieldselector">v1.ResourceFieldSelector</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
......@@ -6024,7 +6086,7 @@ Both these may change in the future. Incoming requests are matched against the h
</div>
<div id="footer">
<div id="footer-text">
Last updated 2016-05-21 03:08:18 UTC
Last updated 2016-05-24 11:53:27 UTC
</div>
</div>
</body>
......
......@@ -2952,6 +2952,13 @@ The resulting set of endpoints can be viewed as:<br>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">resourceFieldRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.</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_resourcefieldselector">v1.ResourceFieldSelector</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">configMapKeyRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Selects a key of a ConfigMap.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
......@@ -3629,6 +3636,54 @@ The resulting set of endpoints can be viewed as:<br>
</div>
<div class="sect2">
<h3 id="_v1_resourcefieldselector">v1.ResourceFieldSelector</h3>
<div class="paragraph">
<p>ResourceFieldSelector represents container resources (cpu, memory) and their output format</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">containerName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Container name: required for volumes, optional for env vars</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">resource</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Required: resource to select</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">divisor</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Specifies the output format of the exposed resources, defaults to "1"</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="_v1_probe">v1.Probe</h3>
<div class="paragraph">
<p>Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic.</p>
......@@ -4092,10 +4147,17 @@ The resulting set of endpoints can be viewed as:<br>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">fieldRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.</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">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_objectfieldselector">v1.ObjectFieldSelector</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">resourceFieldRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.</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_resourcefieldselector">v1.ResourceFieldSelector</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
......@@ -7922,7 +7984,7 @@ The resulting set of endpoints can be viewed as:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2016-05-21 03:08:11 UTC
Last updated 2016-05-24 11:53:20 UTC
</div>
</div>
</body>
......
......@@ -154,6 +154,7 @@ func init() {
DeepCopy_api_ReplicationControllerList,
DeepCopy_api_ReplicationControllerSpec,
DeepCopy_api_ReplicationControllerStatus,
DeepCopy_api_ResourceFieldSelector,
DeepCopy_api_ResourceQuota,
DeepCopy_api_ResourceQuotaList,
DeepCopy_api_ResourceQuotaSpec,
......@@ -666,8 +667,23 @@ func DeepCopy_api_DeleteOptions(in DeleteOptions, out *DeleteOptions, c *convers
func DeepCopy_api_DownwardAPIVolumeFile(in DownwardAPIVolumeFile, out *DownwardAPIVolumeFile, c *conversion.Cloner) error {
out.Path = in.Path
if err := DeepCopy_api_ObjectFieldSelector(in.FieldRef, &out.FieldRef, c); err != nil {
return err
if in.FieldRef != nil {
in, out := in.FieldRef, &out.FieldRef
*out = new(ObjectFieldSelector)
if err := DeepCopy_api_ObjectFieldSelector(*in, *out, c); err != nil {
return err
}
} else {
out.FieldRef = nil
}
if in.ResourceFieldRef != nil {
in, out := in.ResourceFieldRef, &out.ResourceFieldRef
*out = new(ResourceFieldSelector)
if err := DeepCopy_api_ResourceFieldSelector(*in, *out, c); err != nil {
return err
}
} else {
out.ResourceFieldRef = nil
}
return nil
}
......@@ -818,6 +834,15 @@ func DeepCopy_api_EnvVarSource(in EnvVarSource, out *EnvVarSource, c *conversion
} else {
out.FieldRef = nil
}
if in.ResourceFieldRef != nil {
in, out := in.ResourceFieldRef, &out.ResourceFieldRef
*out = new(ResourceFieldSelector)
if err := DeepCopy_api_ResourceFieldSelector(*in, *out, c); err != nil {
return err
}
} else {
out.ResourceFieldRef = nil
}
if in.ConfigMapKeyRef != nil {
in, out := in.ConfigMapKeyRef, &out.ConfigMapKeyRef
*out = new(ConfigMapKeySelector)
......@@ -2572,6 +2597,15 @@ func DeepCopy_api_ReplicationControllerStatus(in ReplicationControllerStatus, ou
return nil
}
func DeepCopy_api_ResourceFieldSelector(in ResourceFieldSelector, out *ResourceFieldSelector, c *conversion.Cloner) error {
out.ContainerName = in.ContainerName
out.Resource = in.Resource
if err := resource.DeepCopy_resource_Quantity(in.Divisor, &out.Divisor, c); err != nil {
return err
}
return nil
}
func DeepCopy_api_ResourceQuota(in ResourceQuota, out *ResourceQuota, c *conversion.Cloner) error {
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
......
......@@ -243,6 +243,7 @@ func FuzzerFor(t *testing.T, version unversioned.GroupVersion, src rand.Source)
func(m *api.DownwardAPIVolumeFile, c fuzz.Continue) {
m.Path = c.RandString()
versions := []string{"v1"}
m.FieldRef = &api.ObjectFieldSelector{}
m.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))]
m.FieldRef.FieldPath = c.RandString()
},
......
......@@ -706,7 +706,10 @@ type DownwardAPIVolumeFile struct {
// Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'
Path string `json:"path"`
// Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.
FieldRef ObjectFieldSelector `json:"fieldRef"`
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
// Selects a resource of the container: only resources limits and requests
// (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.
ResourceFieldRef *ResourceFieldSelector `json:"resourceFieldRef,omitempty"`
}
// AzureFile represents an Azure File Service mount on the host and bind mount to the pod.
......@@ -811,6 +814,9 @@ type EnvVar struct {
type EnvVarSource struct {
// Selects a field of the pod; only name and namespace are supported.
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
// Selects a resource of the container: only resources limits and requests
// (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.
ResourceFieldRef *ResourceFieldSelector `json:"resourceFieldRef,omitempty"`
// Selects a key of a ConfigMap.
ConfigMapKeyRef *ConfigMapKeySelector `json:"configMapKeyRef,omitempty"`
// Selects a key of a secret in the pod's namespace.
......@@ -827,6 +833,16 @@ type ObjectFieldSelector struct {
FieldPath string `json:"fieldPath"`
}
// ResourceFieldSelector represents container resources (cpu, memory) and their output format
type ResourceFieldSelector struct {
// Container name: required for volumes, optional for env vars
ContainerName string `json:"containerName,omitempty"`
// Required: resource to select
Resource string `json:"resource"`
// Specifies the output format of the exposed resources, defaults to "1"
Divisor resource.Quantity `json:"divisor,omitempty"`
}
// Selects a key from a ConfigMap.
type ConfigMapKeySelector struct {
// The ConfigMap to select from.
......
......@@ -269,6 +269,8 @@ func init() {
Convert_api_ReplicationControllerSpec_To_v1_ReplicationControllerSpec,
Convert_v1_ReplicationControllerStatus_To_api_ReplicationControllerStatus,
Convert_api_ReplicationControllerStatus_To_v1_ReplicationControllerStatus,
Convert_v1_ResourceFieldSelector_To_api_ResourceFieldSelector,
Convert_api_ResourceFieldSelector_To_v1_ResourceFieldSelector,
Convert_v1_ResourceQuota_To_api_ResourceQuota,
Convert_api_ResourceQuota_To_v1_ResourceQuota,
Convert_v1_ResourceQuotaList_To_api_ResourceQuotaList,
......@@ -1442,8 +1444,23 @@ func Convert_api_DeleteOptions_To_v1_DeleteOptions(in *api.DeleteOptions, out *D
func autoConvert_v1_DownwardAPIVolumeFile_To_api_DownwardAPIVolumeFile(in *DownwardAPIVolumeFile, out *api.DownwardAPIVolumeFile, s conversion.Scope) error {
out.Path = in.Path
if err := Convert_v1_ObjectFieldSelector_To_api_ObjectFieldSelector(&in.FieldRef, &out.FieldRef, s); err != nil {
return err
if in.FieldRef != nil {
in, out := &in.FieldRef, &out.FieldRef
*out = new(api.ObjectFieldSelector)
if err := Convert_v1_ObjectFieldSelector_To_api_ObjectFieldSelector(*in, *out, s); err != nil {
return err
}
} else {
out.FieldRef = nil
}
if in.ResourceFieldRef != nil {
in, out := &in.ResourceFieldRef, &out.ResourceFieldRef
*out = new(api.ResourceFieldSelector)
if err := Convert_v1_ResourceFieldSelector_To_api_ResourceFieldSelector(*in, *out, s); err != nil {
return err
}
} else {
out.ResourceFieldRef = nil
}
return nil
}
......@@ -1454,8 +1471,23 @@ func Convert_v1_DownwardAPIVolumeFile_To_api_DownwardAPIVolumeFile(in *DownwardA
func autoConvert_api_DownwardAPIVolumeFile_To_v1_DownwardAPIVolumeFile(in *api.DownwardAPIVolumeFile, out *DownwardAPIVolumeFile, s conversion.Scope) error {
out.Path = in.Path
if err := Convert_api_ObjectFieldSelector_To_v1_ObjectFieldSelector(&in.FieldRef, &out.FieldRef, s); err != nil {
return err
if in.FieldRef != nil {
in, out := &in.FieldRef, &out.FieldRef
*out = new(ObjectFieldSelector)
if err := Convert_api_ObjectFieldSelector_To_v1_ObjectFieldSelector(*in, *out, s); err != nil {
return err
}
} else {
out.FieldRef = nil
}
if in.ResourceFieldRef != nil {
in, out := &in.ResourceFieldRef, &out.ResourceFieldRef
*out = new(ResourceFieldSelector)
if err := Convert_api_ResourceFieldSelector_To_v1_ResourceFieldSelector(*in, *out, s); err != nil {
return err
}
} else {
out.ResourceFieldRef = nil
}
return nil
}
......@@ -1811,6 +1843,15 @@ func autoConvert_v1_EnvVarSource_To_api_EnvVarSource(in *EnvVarSource, out *api.
} else {
out.FieldRef = nil
}
if in.ResourceFieldRef != nil {
in, out := &in.ResourceFieldRef, &out.ResourceFieldRef
*out = new(api.ResourceFieldSelector)
if err := Convert_v1_ResourceFieldSelector_To_api_ResourceFieldSelector(*in, *out, s); err != nil {
return err
}
} else {
out.ResourceFieldRef = nil
}
if in.ConfigMapKeyRef != nil {
in, out := &in.ConfigMapKeyRef, &out.ConfigMapKeyRef
*out = new(api.ConfigMapKeySelector)
......@@ -1846,6 +1887,15 @@ func autoConvert_api_EnvVarSource_To_v1_EnvVarSource(in *api.EnvVarSource, out *
} else {
out.FieldRef = nil
}
if in.ResourceFieldRef != nil {
in, out := &in.ResourceFieldRef, &out.ResourceFieldRef
*out = new(ResourceFieldSelector)
if err := Convert_api_ResourceFieldSelector_To_v1_ResourceFieldSelector(*in, *out, s); err != nil {
return err
}
} else {
out.ResourceFieldRef = nil
}
if in.ConfigMapKeyRef != nil {
in, out := &in.ConfigMapKeyRef, &out.ConfigMapKeyRef
*out = new(ConfigMapKeySelector)
......@@ -5646,6 +5696,32 @@ func Convert_api_ReplicationControllerStatus_To_v1_ReplicationControllerStatus(i
return autoConvert_api_ReplicationControllerStatus_To_v1_ReplicationControllerStatus(in, out, s)
}
func autoConvert_v1_ResourceFieldSelector_To_api_ResourceFieldSelector(in *ResourceFieldSelector, out *api.ResourceFieldSelector, s conversion.Scope) error {
out.ContainerName = in.ContainerName
out.Resource = in.Resource
if err := api.Convert_resource_Quantity_To_resource_Quantity(&in.Divisor, &out.Divisor, s); err != nil {
return err
}
return nil
}
func Convert_v1_ResourceFieldSelector_To_api_ResourceFieldSelector(in *ResourceFieldSelector, out *api.ResourceFieldSelector, s conversion.Scope) error {
return autoConvert_v1_ResourceFieldSelector_To_api_ResourceFieldSelector(in, out, s)
}
func autoConvert_api_ResourceFieldSelector_To_v1_ResourceFieldSelector(in *api.ResourceFieldSelector, out *ResourceFieldSelector, s conversion.Scope) error {
out.ContainerName = in.ContainerName
out.Resource = in.Resource
if err := api.Convert_resource_Quantity_To_resource_Quantity(&in.Divisor, &out.Divisor, s); err != nil {
return err
}
return nil
}
func Convert_api_ResourceFieldSelector_To_v1_ResourceFieldSelector(in *api.ResourceFieldSelector, out *ResourceFieldSelector, s conversion.Scope) error {
return autoConvert_api_ResourceFieldSelector_To_v1_ResourceFieldSelector(in, out, s)
}
func autoConvert_v1_ResourceQuota_To_api_ResourceQuota(in *ResourceQuota, out *api.ResourceQuota, s conversion.Scope) error {
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
......
......@@ -151,6 +151,7 @@ func init() {
DeepCopy_v1_ReplicationControllerList,
DeepCopy_v1_ReplicationControllerSpec,
DeepCopy_v1_ReplicationControllerStatus,
DeepCopy_v1_ResourceFieldSelector,
DeepCopy_v1_ResourceQuota,
DeepCopy_v1_ResourceQuotaList,
DeepCopy_v1_ResourceQuotaSpec,
......@@ -644,8 +645,23 @@ func DeepCopy_v1_DeleteOptions(in DeleteOptions, out *DeleteOptions, c *conversi
func DeepCopy_v1_DownwardAPIVolumeFile(in DownwardAPIVolumeFile, out *DownwardAPIVolumeFile, c *conversion.Cloner) error {
out.Path = in.Path
if err := DeepCopy_v1_ObjectFieldSelector(in.FieldRef, &out.FieldRef, c); err != nil {
return err
if in.FieldRef != nil {
in, out := in.FieldRef, &out.FieldRef
*out = new(ObjectFieldSelector)
if err := DeepCopy_v1_ObjectFieldSelector(*in, *out, c); err != nil {
return err
}
} else {
out.FieldRef = nil
}
if in.ResourceFieldRef != nil {
in, out := in.ResourceFieldRef, &out.ResourceFieldRef
*out = new(ResourceFieldSelector)
if err := DeepCopy_v1_ResourceFieldSelector(*in, *out, c); err != nil {
return err
}
} else {
out.ResourceFieldRef = nil
}
return nil
}
......@@ -796,6 +812,15 @@ func DeepCopy_v1_EnvVarSource(in EnvVarSource, out *EnvVarSource, c *conversion.
} else {
out.FieldRef = nil
}
if in.ResourceFieldRef != nil {
in, out := in.ResourceFieldRef, &out.ResourceFieldRef
*out = new(ResourceFieldSelector)
if err := DeepCopy_v1_ResourceFieldSelector(*in, *out, c); err != nil {
return err
}
} else {
out.ResourceFieldRef = nil
}
if in.ConfigMapKeyRef != nil {
in, out := in.ConfigMapKeyRef, &out.ConfigMapKeyRef
*out = new(ConfigMapKeySelector)
......@@ -2526,6 +2551,15 @@ func DeepCopy_v1_ReplicationControllerStatus(in ReplicationControllerStatus, out
return nil
}
func DeepCopy_v1_ResourceFieldSelector(in ResourceFieldSelector, out *ResourceFieldSelector, c *conversion.Cloner) error {
out.ContainerName = in.ContainerName
out.Resource = in.Resource
if err := resource.DeepCopy_resource_Quantity(in.Divisor, &out.Divisor, c); err != nil {
return err
}
return nil
}
func DeepCopy_v1_ResourceQuota(in ResourceQuota, out *ResourceQuota, c *conversion.Cloner) error {
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
......
......@@ -504,6 +504,10 @@ message DownwardAPIVolumeFile {
// Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.
optional ObjectFieldSelector fieldRef = 2;
// Selects a resource of the container: only resources limits and requests
// (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.
optional ResourceFieldSelector resourceFieldRef = 3;
}
// DownwardAPIVolumeSource represents a volume containing downward API info.
......@@ -641,11 +645,15 @@ message EnvVarSource {
// Selects a field of the pod; only name and namespace are supported.
optional ObjectFieldSelector fieldRef = 1;
// Selects a resource of the container: only resources limits and requests
// (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.
optional ResourceFieldSelector resourceFieldRef = 2;
// Selects a key of a ConfigMap.
optional ConfigMapKeySelector configMapKeyRef = 2;
optional ConfigMapKeySelector configMapKeyRef = 3;
// Selects a key of a secret in the pod's namespace
optional SecretKeySelector secretKeyRef = 3;
optional SecretKeySelector secretKeyRef = 4;
}
// Event is a report of an event somewhere in the cluster.
......@@ -2345,6 +2353,18 @@ message ReplicationControllerStatus {
optional int64 observedGeneration = 3;
}
// ResourceFieldSelector represents container resources (cpu, memory) and their output format
message ResourceFieldSelector {
// Container name: required for volumes, optional for env vars
optional string containerName = 1;
// Required: resource to select
optional string resource = 2;
// Specifies the output format of the exposed resources, defaults to "1"
optional k8s.io.kubernetes.pkg.api.resource.Quantity divisor = 3;
}
// ResourceQuota sets aggregate quota restrictions enforced per namespace
message ResourceQuota {
// Standard object's metadata.
......
......@@ -938,10 +938,13 @@ type EnvVar struct {
type EnvVarSource struct {
// Selects a field of the pod; only name and namespace are supported.
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty" protobuf:"bytes,1,opt,name=fieldRef"`
// Selects a resource of the container: only resources limits and requests
// (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.
ResourceFieldRef *ResourceFieldSelector `json:"resourceFieldRef,omitempty" protobuf:"bytes,2,opt,name=resourceFieldRef"`
// Selects a key of a ConfigMap.
ConfigMapKeyRef *ConfigMapKeySelector `json:"configMapKeyRef,omitempty" protobuf:"bytes,2,opt,name=configMapKeyRef"`
ConfigMapKeyRef *ConfigMapKeySelector `json:"configMapKeyRef,omitempty" protobuf:"bytes,3,opt,name=configMapKeyRef"`
// Selects a key of a secret in the pod's namespace
SecretKeyRef *SecretKeySelector `json:"secretKeyRef,omitempty" protobuf:"bytes,3,opt,name=secretKeyRef"`
SecretKeyRef *SecretKeySelector `json:"secretKeyRef,omitempty" protobuf:"bytes,4,opt,name=secretKeyRef"`
}
// ObjectFieldSelector selects an APIVersioned field of an object.
......@@ -952,6 +955,16 @@ type ObjectFieldSelector struct {
FieldPath string `json:"fieldPath" protobuf:"bytes,2,opt,name=fieldPath"`
}
// ResourceFieldSelector represents container resources (cpu, memory) and their output format
type ResourceFieldSelector struct {
// Container name: required for volumes, optional for env vars
ContainerName string `json:"containerName,omitempty" protobuf:"bytes,1,opt,name=containerName"`
// Required: resource to select
Resource string `json:"resource" protobuf:"bytes,2,opt,name=resource"`
// Specifies the output format of the exposed resources, defaults to "1"
Divisor resource.Quantity `json:"divisor,omitempty" protobuf:"bytes,3,opt,name=divisor"`
}
// Selects a key from a ConfigMap.
type ConfigMapKeySelector struct {
// The ConfigMap to select from.
......@@ -3202,7 +3215,10 @@ type DownwardAPIVolumeFile struct {
// Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'
Path string `json:"path" protobuf:"bytes,1,opt,name=path"`
// Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.
FieldRef ObjectFieldSelector `json:"fieldRef" protobuf:"bytes,2,opt,name=fieldRef"`
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty" protobuf:"bytes,2,opt,name=fieldRef"`
// Selects a resource of the container: only resources limits and requests
// (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.
ResourceFieldRef *ResourceFieldSelector `json:"resourceFieldRef,omitempty" protobuf:"bytes,3,opt,name=resourceFieldRef"`
}
// SecurityContext holds security configuration that will be applied to a container.
......
......@@ -307,9 +307,10 @@ func (DeleteOptions) SwaggerDoc() map[string]string {
}
var map_DownwardAPIVolumeFile = map[string]string{
"": "DownwardAPIVolumeFile represents information to create the file containing the pod field",
"path": "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'",
"fieldRef": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.",
"": "DownwardAPIVolumeFile represents information to create the file containing the pod field",
"path": "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'",
"fieldRef": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.",
"resourceFieldRef": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.",
}
func (DownwardAPIVolumeFile) SwaggerDoc() map[string]string {
......@@ -399,10 +400,11 @@ func (EnvVar) SwaggerDoc() map[string]string {
}
var map_EnvVarSource = map[string]string{
"": "EnvVarSource represents a source for the value of an EnvVar.",
"fieldRef": "Selects a field of the pod; only name and namespace are supported.",
"configMapKeyRef": "Selects a key of a ConfigMap.",
"secretKeyRef": "Selects a key of a secret in the pod's namespace",
"": "EnvVarSource represents a source for the value of an EnvVar.",
"fieldRef": "Selects a field of the pod; only name and namespace are supported.",
"resourceFieldRef": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.",
"configMapKeyRef": "Selects a key of a ConfigMap.",
"secretKeyRef": "Selects a key of a secret in the pod's namespace",
}
func (EnvVarSource) SwaggerDoc() map[string]string {
......@@ -1394,6 +1396,17 @@ func (ReplicationControllerStatus) SwaggerDoc() map[string]string {
return map_ReplicationControllerStatus
}
var map_ResourceFieldSelector = map[string]string{
"": "ResourceFieldSelector represents container resources (cpu, memory) and their output format",
"containerName": "Container name: required for volumes, optional for env vars",
"resource": "Required: resource to select",
"divisor": "Specifies the output format of the exposed resources, defaults to \"1\"",
}
func (ResourceFieldSelector) SwaggerDoc() map[string]string {
return map_ResourceFieldSelector
}
var map_ResourceQuota = map[string]string{
"": "ResourceQuota sets aggregate quota restrictions enforced per namespace",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
......
......@@ -702,7 +702,16 @@ func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSou
allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
}
allErrs = append(allErrs, validateVolumeSourcePath(downwardAPIVolumeFile.Path, fldPath.Child("path"))...)
allErrs = append(allErrs, validateObjectFieldSelector(&downwardAPIVolumeFile.FieldRef, &validDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...)
if downwardAPIVolumeFile.FieldRef != nil {
allErrs = append(allErrs, validateObjectFieldSelector(downwardAPIVolumeFile.FieldRef, &validDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...)
if downwardAPIVolumeFile.ResourceFieldRef != nil {
allErrs = append(allErrs, field.Invalid(fldPath, "resource", "fieldRef and resourceFieldRef can not be specified simultaneously"))
}
} else if downwardAPIVolumeFile.ResourceFieldRef != nil {
allErrs = append(allErrs, validateContainerResourceFieldSelector(downwardAPIVolumeFile.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), true)...)
} else {
allErrs = append(allErrs, field.Required(fldPath, "one of fieldRef and resourceFieldRef is required"))
}
}
return allErrs
}
......@@ -1048,6 +1057,7 @@ func validateEnv(vars []api.EnvVar, fldPath *field.Path) field.ErrorList {
}
var validFieldPathExpressionsEnv = sets.NewString("metadata.name", "metadata.namespace", "status.podIP")
var validContainerResourceFieldPathExpressions = sets.NewString("limits.cpu", "limits.memory", "requests.cpu", "requests.memory")
func validateEnvVarValueFrom(ev api.EnvVar, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
......@@ -1062,6 +1072,10 @@ func validateEnvVarValueFrom(ev api.EnvVar, fldPath *field.Path) field.ErrorList
numSources++
allErrs = append(allErrs, validateObjectFieldSelector(ev.ValueFrom.FieldRef, &validFieldPathExpressionsEnv, fldPath.Child("fieldRef"))...)
}
if ev.ValueFrom.ResourceFieldRef != nil {
numSources++
allErrs = append(allErrs, validateContainerResourceFieldSelector(ev.ValueFrom.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), false)...)
}
if ev.ValueFrom.ConfigMapKeyRef != nil {
numSources++
allErrs = append(allErrs, validateConfigMapKeySelector(ev.ValueFrom.ConfigMapKeyRef, fldPath.Child("configMapKeyRef"))...)
......@@ -1101,6 +1115,42 @@ func validateObjectFieldSelector(fs *api.ObjectFieldSelector, expressions *sets.
return allErrs
}
func validateContainerResourceFieldSelector(fs *api.ResourceFieldSelector, expressions *sets.String, fldPath *field.Path, volume bool) field.ErrorList {
allErrs := field.ErrorList{}
if volume && len(fs.ContainerName) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("containerName"), ""))
} else if len(fs.Resource) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("resource"), ""))
} else if !expressions.Has(fs.Resource) {
allErrs = append(allErrs, field.NotSupported(fldPath.Child("resource"), fs.Resource, expressions.List()))
}
allErrs = append(allErrs, validateContainerResourceDivisor(fs.Resource, fs.Divisor, fldPath)...)
return allErrs
}
var validContainerResourceDivisorForCPU = sets.NewString("1m", "1")
var validContainerResourceDivisorForMemory = sets.NewString("1m", "1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei")
func validateContainerResourceDivisor(rName string, divisor resource.Quantity, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
unsetDivisor := resource.Quantity{}
if unsetDivisor.Cmp(divisor) == 0 {
return allErrs
}
switch rName {
case "limits.cpu", "requests.cpu":
if !validContainerResourceDivisorForCPU.Has(divisor.String()) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, fmt.Sprintf("only divisor's values 1m and 1 are supported with the cpu resource")))
}
case "limits.memory", "requests.memory":
if !validContainerResourceDivisorForMemory.Has(divisor.String()) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, fmt.Sprintf("only divisor's values 1m, 1, 1k, 1M, 1G, 1T, 1P, 1E, 1Ki, 1Mi, 1Gi, 1Ti, 1Pi, 1Ei are supported with the memory resource")))
}
}
return allErrs
}
func validateConfigMapKeySelector(s *api.ConfigMapKeySelector, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
......
......@@ -656,30 +656,42 @@ func TestValidateVolumes(t *testing.T) {
{Name: "cinder", VolumeSource: api.VolumeSource{Cinder: &api.CinderVolumeSource{VolumeID: "29ea5088-4f60-4757-962e-dba678767887", FSType: "ext4", ReadOnly: false}}},
{Name: "cephfs", VolumeSource: api.VolumeSource{CephFS: &api.CephFSVolumeSource{Monitors: []string{"foo"}}}},
{Name: "downwardapi", VolumeSource: api.VolumeSource{DownwardAPI: &api.DownwardAPIVolumeSource{Items: []api.DownwardAPIVolumeFile{
{Path: "labels", FieldRef: api.ObjectFieldSelector{
{Path: "labels", FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}},
{Path: "annotations", FieldRef: api.ObjectFieldSelector{
{Path: "annotations", FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.annotations"}},
{Path: "namespace", FieldRef: api.ObjectFieldSelector{
{Path: "namespace", FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.namespace"}},
{Path: "name", FieldRef: api.ObjectFieldSelector{
{Path: "name", FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.name"}},
{Path: "path/withslash/andslash", FieldRef: api.ObjectFieldSelector{
{Path: "path/withslash/andslash", FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}},
{Path: "path/./withdot", FieldRef: api.ObjectFieldSelector{
{Path: "path/./withdot", FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}},
{Path: "path/with..dot", FieldRef: api.ObjectFieldSelector{
{Path: "path/with..dot", FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}},
{Path: "second-level-dirent-can-have/..dot", FieldRef: api.ObjectFieldSelector{
{Path: "second-level-dirent-can-have/..dot", FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}},
{Path: "cpu_limit", ResourceFieldRef: &api.ResourceFieldSelector{
ContainerName: "test-container",
Resource: "limits.cpu"}},
{Path: "cpu_request", ResourceFieldRef: &api.ResourceFieldSelector{
ContainerName: "test-container",
Resource: "requests.cpu"}},
{Path: "memory_limit", ResourceFieldRef: &api.ResourceFieldSelector{
ContainerName: "test-container",
Resource: "limits.memory"}},
{Path: "memory_request", ResourceFieldRef: &api.ResourceFieldSelector{
ContainerName: "test-container",
Resource: "requests.memory"}},
}}}},
{Name: "fc", VolumeSource: api.VolumeSource{FC: &api.FCVolumeSource{TargetWWNs: []string{"some_wwn"}, Lun: &lun, FSType: "ext4", ReadOnly: false}}},
{Name: "flexvolume", VolumeSource: api.VolumeSource{FlexVolume: &api.FlexVolumeSource{Driver: "kubernetes.io/blue", FSType: "ext4"}}},
......@@ -705,30 +717,38 @@ func TestValidateVolumes(t *testing.T) {
containsDots := api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{Repository: "foo", Directory: "dots/../bar"}}
absPath := api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{Repository: "foo", Directory: "/abstarget"}}
emptyPathName := api.VolumeSource{DownwardAPI: &api.DownwardAPIVolumeSource{Items: []api.DownwardAPIVolumeFile{{Path: "",
FieldRef: api.ObjectFieldSelector{
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}}},
}}
absolutePathName := api.VolumeSource{DownwardAPI: &api.DownwardAPIVolumeSource{Items: []api.DownwardAPIVolumeFile{{Path: "/absolutepath",
FieldRef: api.ObjectFieldSelector{
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}}},
}}
dotDotInPath := api.VolumeSource{DownwardAPI: &api.DownwardAPIVolumeSource{Items: []api.DownwardAPIVolumeFile{{Path: "../../passwd",
FieldRef: api.ObjectFieldSelector{
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}}},
}}
dotDotPathName := api.VolumeSource{DownwardAPI: &api.DownwardAPIVolumeSource{Items: []api.DownwardAPIVolumeFile{{Path: "..badFileName",
FieldRef: api.ObjectFieldSelector{
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}}},
}}
dotDotFirstLevelDirent := api.VolumeSource{DownwardAPI: &api.DownwardAPIVolumeSource{Items: []api.DownwardAPIVolumeFile{{Path: "..badDirName/goodFileName",
FieldRef: api.ObjectFieldSelector{
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"}}},
}}
fieldRefandResourceFieldRef := api.VolumeSource{DownwardAPI: &api.DownwardAPIVolumeSource{Items: []api.DownwardAPIVolumeFile{{Path: "test",
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels"},
ResourceFieldRef: &api.ResourceFieldSelector{
ContainerName: "test-container",
Resource: "requests.memory"}}},
}}
zeroWWN := api.VolumeSource{FC: &api.FCVolumeSource{TargetWWNs: []string{}, Lun: &lun, FSType: "ext4", ReadOnly: false}}
emptyLun := api.VolumeSource{FC: &api.FCVolumeSource{TargetWWNs: []string{"wwn"}, Lun: nil, FSType: "ext4", ReadOnly: false}}
slashInName := api.VolumeSource{Flocker: &api.FlockerVolumeSource{DatasetName: "foo/bar"}}
......@@ -865,6 +885,11 @@ func TestValidateVolumes(t *testing.T) {
field.ErrorTypeRequired,
"azureFile.shareName", "",
},
"fieldRef and ResourceFieldRef together": {
[]api.Volume{{Name: "testvolume", VolumeSource: fieldRefandResourceFieldRef}},
field.ErrorTypeInvalid,
"downwardAPI", "fieldRef and resourceFieldRef can not be specified simultaneously",
},
}
for k, v := range errorCases {
_, errs := validateVolumes(v.V, field.NewPath("field"))
......
......@@ -18,8 +18,12 @@ package fieldpath
import (
"fmt"
"math"
"strconv"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/resource"
)
// formatMap formats map[string]string to a string.
......@@ -58,3 +62,61 @@ func ExtractFieldPathAsString(obj interface{}, fieldPath string) (string, error)
return "", fmt.Errorf("Unsupported fieldPath: %v", fieldPath)
}
// ExtractResourceValueByContainerName extracts the value of a resource
// by providing container name
func ExtractResourceValueByContainerName(fs *api.ResourceFieldSelector, pod *api.Pod, containerName string) (string, error) {
container, err := findContainerInPod(pod, containerName)
if err != nil {
return "", err
}
return ExtractContainerResourceValue(fs, container)
}
// ExtractContainerResourceValue extracts the value of a resource
// in an already known container
func ExtractContainerResourceValue(fs *api.ResourceFieldSelector, container *api.Container) (string, error) {
divisor := resource.Quantity{}
if divisor.Cmp(fs.Divisor) == 0 {
divisor = resource.MustParse("1")
} else {
divisor = fs.Divisor
}
switch fs.Resource {
case "limits.cpu":
return convertResourceCPUToString(container.Resources.Limits.Cpu(), divisor)
case "limits.memory":
return convertResourceMemoryToString(container.Resources.Limits.Memory(), divisor)
case "requests.cpu":
return convertResourceCPUToString(container.Resources.Requests.Cpu(), divisor)
case "requests.memory":
return convertResourceMemoryToString(container.Resources.Requests.Memory(), divisor)
}
return "", fmt.Errorf("Unsupported container resource : %v", fs.Resource)
}
// findContainerInPod finds a container by its name in the provided pod
func findContainerInPod(pod *api.Pod, containerName string) (*api.Container, error) {
for _, container := range pod.Spec.Containers {
if container.Name == containerName {
return &container, nil
}
}
return nil, fmt.Errorf("container %s not found", containerName)
}
// convertResourceCPUTOString converts cpu value to the format of divisor and returns
// ceiling of the value.
func convertResourceCPUToString(cpu *resource.Quantity, divisor resource.Quantity) (string, error) {
c := int64(math.Ceil(float64(cpu.MilliValue()) / float64(divisor.MilliValue())))
return strconv.FormatInt(c, 10), nil
}
// convertResourceMemoryToString converts memory value to the format of divisor and returns
// ceiling of the value.
func convertResourceMemoryToString(memory *resource.Quantity, divisor resource.Quantity) (string, error) {
m := int64(math.Ceil(float64(memory.Value()) / float64(divisor.Value())))
return strconv.FormatInt(m, 10), nil
}
......@@ -700,7 +700,12 @@ func printRBDVolumeSource(rbd *api.RBDVolumeSource, out io.Writer) {
func printDownwardAPIVolumeSource(d *api.DownwardAPIVolumeSource, out io.Writer) {
fmt.Fprintf(out, " Type:\tDownwardAPI (a volume populated by information about the pod)\n Items:\n")
for _, mapping := range d.Items {
fmt.Fprintf(out, " %v -> %v\n", mapping.FieldRef.FieldPath, mapping.Path)
if mapping.FieldRef != nil {
fmt.Fprintf(out, " %v -> %v\n", mapping.FieldRef.FieldPath, mapping.Path)
}
if mapping.ResourceFieldRef != nil {
fmt.Fprintf(out, " %v -> %v\n", mapping.ResourceFieldRef.Resource, mapping.Path)
}
}
}
......@@ -895,6 +900,12 @@ func describeContainers(label string, containers []api.Container, containerStatu
valueFrom = resolverFn(e)
}
fmt.Fprintf(out, " %s:\t%s (%s:%s)\n", e.Name, valueFrom, e.ValueFrom.FieldRef.APIVersion, e.ValueFrom.FieldRef.FieldPath)
case e.ValueFrom.ResourceFieldRef != nil:
valueFrom, err := fieldpath.ExtractContainerResourceValue(e.ValueFrom.ResourceFieldRef, &container)
if err != nil {
valueFrom = ""
}
fmt.Fprintf(out, " %s:\t%s (%s)\n", e.Name, valueFrom, e.ValueFrom.ResourceFieldRef.Resource)
case e.ValueFrom.SecretKeyRef != nil:
fmt.Fprintf(out, " %s:\t<set to the key '%s' in secret '%s'>\n", e.Name, e.ValueFrom.SecretKeyRef.Key, e.ValueFrom.SecretKeyRef.Name)
case e.ValueFrom.ConfigMapKeyRef != nil:
......
......@@ -1506,6 +1506,11 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *api.Pod, container *api.Contain
if err != nil {
return result, err
}
case envVar.ValueFrom.ResourceFieldRef != nil:
runtimeVal, err = containerResourceRuntimeValue(envVar.ValueFrom.ResourceFieldRef, pod, container)
if err != nil {
return result, err
}
case envVar.ValueFrom.ConfigMapKeyRef != nil:
name := envVar.ValueFrom.ConfigMapKeyRef.Name
key := envVar.ValueFrom.ConfigMapKeyRef.Key
......@@ -1563,6 +1568,16 @@ func (kl *Kubelet) podFieldSelectorRuntimeValue(fs *api.ObjectFieldSelector, pod
return fieldpath.ExtractFieldPathAsString(pod, internalFieldPath)
}
// containerResourceRuntimeValue returns the value of the provided container resource
func containerResourceRuntimeValue(fs *api.ResourceFieldSelector, pod *api.Pod, container *api.Container) (string, error) {
containerName := fs.ContainerName
if len(containerName) == 0 {
return fieldpath.ExtractContainerResourceValue(fs, container)
} else {
return fieldpath.ExtractResourceValueByContainerName(fs, pod, containerName)
}
}
// GetClusterDNS returns a list of the DNS servers and a list of the DNS search
// domains of the cluster.
func (kl *Kubelet) GetClusterDNS(pod *api.Pod) ([]string, []string, error) {
......
......@@ -69,14 +69,11 @@ func (plugin *downwardAPIPlugin) CanSupport(spec *volume.Spec) bool {
func (plugin *downwardAPIPlugin) NewMounter(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Mounter, error) {
v := &downwardAPIVolume{
volName: spec.Name(),
items: spec.Volume.DownwardAPI.Items,
pod: pod,
podUID: pod.UID,
plugin: plugin,
}
v.fieldReferenceFileNames = make(map[string]string)
for _, fileInfo := range spec.Volume.DownwardAPI.Items {
v.fieldReferenceFileNames[fileInfo.FieldRef.FieldPath] = path.Clean(fileInfo.Path)
}
return &downwardAPIVolumeMounter{
downwardAPIVolume: v,
opts: &opts,
......@@ -95,11 +92,11 @@ func (plugin *downwardAPIPlugin) NewUnmounter(volName string, podUID types.UID)
// downwardAPIVolume retrieves downward API data and placing them into the volume on the host.
type downwardAPIVolume struct {
volName string
fieldReferenceFileNames map[string]string
pod *api.Pod
podUID types.UID // TODO: remove this redundancy as soon NewUnmounter func will have *api.POD and not only types.UID
plugin *downwardAPIPlugin
volName string
items []api.DownwardAPIVolumeFile
pod *api.Pod
podUID types.UID // TODO: remove this redundancy as soon NewUnmounter func will have *api.POD and not only types.UID
plugin *downwardAPIPlugin
volume.MetricsNil
}
......@@ -173,12 +170,22 @@ func (b *downwardAPIVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
func (d *downwardAPIVolume) collectData() (map[string][]byte, error) {
errlist := []error{}
data := make(map[string][]byte)
for fieldReference, fileName := range d.fieldReferenceFileNames {
if values, err := fieldpath.ExtractFieldPathAsString(d.pod, fieldReference); err != nil {
glog.Errorf("Unable to extract field %s: %s", fieldReference, err.Error())
errlist = append(errlist, err)
} else {
data[fileName] = []byte(sortLines(values))
for _, fileInfo := range d.items {
if fileInfo.FieldRef != nil {
if values, err := fieldpath.ExtractFieldPathAsString(d.pod, fileInfo.FieldRef.FieldPath); err != nil {
glog.Errorf("Unable to extract field %s: %s", fileInfo.FieldRef.FieldPath, err.Error())
errlist = append(errlist, err)
} else {
data[path.Clean(fileInfo.Path)] = []byte(sortLines(values))
}
} else if fileInfo.ResourceFieldRef != nil {
containerName := fileInfo.ResourceFieldRef.ContainerName
if values, err := fieldpath.ExtractResourceValueByContainerName(fileInfo.ResourceFieldRef, d.pod, containerName); err != nil {
glog.Errorf("Unable to extract field %s: %s", fileInfo.ResourceFieldRef.Resource, err.Error())
errlist = append(errlist, err)
} else {
data[path.Clean(fileInfo.Path)] = []byte(sortLines(values))
}
}
}
return data, utilerrors.NewAggregate(errlist)
......
......@@ -115,7 +115,7 @@ func TestLabels(t *testing.T) {
VolumeSource: api.VolumeSource{
DownwardAPI: &api.DownwardAPIVolumeSource{
Items: []api.DownwardAPIVolumeFile{
{Path: "labels", FieldRef: api.ObjectFieldSelector{
{Path: "labels", FieldRef: &api.ObjectFieldSelector{
FieldPath: "metadata.labels"}}}},
},
}
......@@ -179,7 +179,7 @@ func TestAnnotations(t *testing.T) {
VolumeSource: api.VolumeSource{
DownwardAPI: &api.DownwardAPIVolumeSource{
Items: []api.DownwardAPIVolumeFile{
{Path: "annotations", FieldRef: api.ObjectFieldSelector{
{Path: "annotations", FieldRef: &api.ObjectFieldSelector{
FieldPath: "metadata.annotations"}}}},
},
}
......@@ -242,7 +242,7 @@ func TestName(t *testing.T) {
VolumeSource: api.VolumeSource{
DownwardAPI: &api.DownwardAPIVolumeSource{
Items: []api.DownwardAPIVolumeFile{
{Path: "name_file_name", FieldRef: api.ObjectFieldSelector{
{Path: "name_file_name", FieldRef: &api.ObjectFieldSelector{
FieldPath: "metadata.name"}}}},
},
}
......@@ -305,7 +305,7 @@ func TestNamespace(t *testing.T) {
VolumeSource: api.VolumeSource{
DownwardAPI: &api.DownwardAPIVolumeSource{
Items: []api.DownwardAPIVolumeFile{
{Path: "namespace_file_name", FieldRef: api.ObjectFieldSelector{
{Path: "namespace_file_name", FieldRef: &api.ObjectFieldSelector{
FieldPath: "metadata.namespace"}}}},
},
}
......@@ -383,7 +383,7 @@ func TestWriteTwiceNoUpdate(t *testing.T) {
VolumeSource: api.VolumeSource{
DownwardAPI: &api.DownwardAPIVolumeSource{
Items: []api.DownwardAPIVolumeFile{
{Path: "labels", FieldRef: api.ObjectFieldSelector{
{Path: "labels", FieldRef: &api.ObjectFieldSelector{
FieldPath: "metadata.labels"}}}},
},
}
......@@ -469,7 +469,7 @@ func TestWriteTwiceWithUpdate(t *testing.T) {
VolumeSource: api.VolumeSource{
DownwardAPI: &api.DownwardAPIVolumeSource{
Items: []api.DownwardAPIVolumeFile{
{Path: "labels", FieldRef: api.ObjectFieldSelector{
{Path: "labels", FieldRef: &api.ObjectFieldSelector{
FieldPath: "metadata.labels"}}}},
},
}
......@@ -575,9 +575,9 @@ func TestWriteWithUnixPath(t *testing.T) {
VolumeSource: api.VolumeSource{
DownwardAPI: &api.DownwardAPIVolumeSource{
Items: []api.DownwardAPIVolumeFile{
{Path: "this/is/mine/labels", FieldRef: api.ObjectFieldSelector{
{Path: "this/is/mine/labels", FieldRef: &api.ObjectFieldSelector{
FieldPath: "metadata.labels"}},
{Path: "this/is/yours/annotations", FieldRef: api.ObjectFieldSelector{
{Path: "this/is/yours/annotations", FieldRef: &api.ObjectFieldSelector{
FieldPath: "metadata.annotations"}},
}}},
}
......@@ -657,7 +657,7 @@ func TestWriteWithUnixPathBadPath(t *testing.T) {
Items: []api.DownwardAPIVolumeFile{
{
Path: "this//labels",
FieldRef: api.ObjectFieldSelector{
FieldRef: &api.ObjectFieldSelector{
FieldPath: "metadata.labels",
},
},
......
......@@ -20,6 +20,7 @@ import (
"fmt"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/test/e2e/framework"
......@@ -80,6 +81,53 @@ var _ = framework.KubeDescribe("Downward API", func() {
testDownwardAPI(f, podName, env, expectations)
})
It("should provide container's limits.cpu/memory and requests.cpu/memory as env vars", func() {
podName := "downward-api-" + string(util.NewUUID())
env := []api.EnvVar{
{
Name: "CPU_LIMIT",
ValueFrom: &api.EnvVarSource{
ResourceFieldRef: &api.ResourceFieldSelector{
Resource: "limits.cpu",
},
},
},
{
Name: "MEMORY_LIMIT",
ValueFrom: &api.EnvVarSource{
ResourceFieldRef: &api.ResourceFieldSelector{
Resource: "limits.memory",
},
},
},
{
Name: "CPU_REQUEST",
ValueFrom: &api.EnvVarSource{
ResourceFieldRef: &api.ResourceFieldSelector{
Resource: "requests.cpu",
},
},
},
{
Name: "MEMORY_REQUEST",
ValueFrom: &api.EnvVarSource{
ResourceFieldRef: &api.ResourceFieldSelector{
Resource: "requests.memory",
},
},
},
}
expectations := []string{
fmt.Sprintf("CPU_LIMIT=2"),
fmt.Sprintf("MEMORY_LIMIT=67108864"),
fmt.Sprintf("CPU_REQUEST=1"),
fmt.Sprintf("MEMORY_REQUEST=33554432"),
}
testDownwardAPI(f, podName, env, expectations)
})
})
func testDownwardAPI(f *framework.Framework, podName string, env []api.EnvVar, expectations []string) {
......@@ -94,7 +142,17 @@ func testDownwardAPI(f *framework.Framework, podName string, env []api.EnvVar, e
Name: "dapi-container",
Image: "gcr.io/google_containers/busybox:1.24",
Command: []string{"sh", "-c", "env"},
Env: env,
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("250m"),
api.ResourceMemory: resource.MustParse("32Mi"),
},
Limits: api.ResourceList{
api.ResourceCPU: resource.MustParse("1250m"),
api.ResourceMemory: resource.MustParse("64Mi"),
},
},
Env: env,
},
},
RestartPolicy: api.RestartPolicyNever,
......
......@@ -21,6 +21,7 @@ import (
"time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/test/e2e/framework"
......@@ -131,6 +132,43 @@ var _ = framework.KubeDescribe("Downward API volume", func() {
podLogTimeout, framework.Poll).Should(ContainSubstring("builder=\"foo\"\n"))
})
It("should provide container's cpu limit", func() {
podName := "downwardapi-volume-" + string(util.NewUUID())
pod := downwardAPIVolumeForContainerResources(podName, "/etc/cpu_limit")
framework.TestContainerOutput("downward API volume plugin", f.Client, pod, 0, []string{
fmt.Sprintf("2\n"),
}, f.Namespace.Name)
})
It("should provide container's memory limit", func() {
podName := "downwardapi-volume-" + string(util.NewUUID())
pod := downwardAPIVolumeForContainerResources(podName, "/etc/memory_limit")
framework.TestContainerOutput("downward API volume plugin", f.Client, pod, 0, []string{
fmt.Sprintf("67108864\n"),
}, f.Namespace.Name)
})
It("should provide container's cpu request", func() {
podName := "downwardapi-volume-" + string(util.NewUUID())
pod := downwardAPIVolumeForContainerResources(podName, "/etc/cpu_request")
framework.TestContainerOutput("downward API volume plugin", f.Client, pod, 0, []string{
fmt.Sprintf("1\n"),
}, f.Namespace.Name)
})
It("should provide container's memory request", func() {
podName := "downwardapi-volume-" + string(util.NewUUID())
pod := downwardAPIVolumeForContainerResources(podName, "/etc/memory_request")
framework.TestContainerOutput("downward API volume plugin", f.Client, pod, 0, []string{
fmt.Sprintf("33554432\n"),
}, f.Namespace.Name)
})
})
func downwardAPIVolumePodForSimpleTest(name string, filePath string) *api.Pod {
......@@ -154,6 +192,40 @@ func downwardAPIVolumePodForSimpleTest(name string, filePath string) *api.Pod {
return pod
}
func downwardAPIVolumeForContainerResources(name string, filePath string) *api.Pod {
pod := downwardAPIVolumeBasePod(name, nil, nil)
pod.Spec.Containers = downwardAPIVolumeBaseContainers("client-container", filePath)
return pod
}
func downwardAPIVolumeBaseContainers(name, filePath string) []api.Container {
return []api.Container{
{
Name: name,
Image: "gcr.io/google_containers/mounttest:0.6",
Command: []string{"/mt", "--file_content=" + filePath},
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceCPU: resource.MustParse("250m"),
api.ResourceMemory: resource.MustParse("32Mi"),
},
Limits: api.ResourceList{
api.ResourceCPU: resource.MustParse("1250m"),
api.ResourceMemory: resource.MustParse("64Mi"),
},
},
VolumeMounts: []api.VolumeMount{
{
Name: "podinfo",
MountPath: "/etc",
ReadOnly: false,
},
},
},
}
}
func downwardAPIVolumePodForUpdateTest(name string, labels, annotations map[string]string, filePath string) *api.Pod {
pod := downwardAPIVolumeBasePod(name, labels, annotations)
......@@ -192,11 +264,39 @@ func downwardAPIVolumeBasePod(name string, labels, annotations map[string]string
Items: []api.DownwardAPIVolumeFile{
{
Path: "podname",
FieldRef: api.ObjectFieldSelector{
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.name",
},
},
{
Path: "cpu_limit",
ResourceFieldRef: &api.ResourceFieldSelector{
ContainerName: "client-container",
Resource: "limits.cpu",
},
},
{
Path: "cpu_request",
ResourceFieldRef: &api.ResourceFieldSelector{
ContainerName: "client-container",
Resource: "requests.cpu",
},
},
{
Path: "memory_limit",
ResourceFieldRef: &api.ResourceFieldSelector{
ContainerName: "client-container",
Resource: "limits.memory",
},
},
{
Path: "memory_request",
ResourceFieldRef: &api.ResourceFieldSelector{
ContainerName: "client-container",
Resource: "requests.memory",
},
},
},
},
},
......@@ -213,7 +313,7 @@ func applyLabelsAndAnnotationsToDownwardAPIPod(labels, annotations map[string]st
if len(labels) > 0 {
pod.Spec.Volumes[0].DownwardAPI.Items = append(pod.Spec.Volumes[0].DownwardAPI.Items, api.DownwardAPIVolumeFile{
Path: "labels",
FieldRef: api.ObjectFieldSelector{
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.labels",
},
......@@ -223,7 +323,7 @@ func applyLabelsAndAnnotationsToDownwardAPIPod(labels, annotations map[string]st
if len(annotations) > 0 {
pod.Spec.Volumes[0].DownwardAPI.Items = append(pod.Spec.Volumes[0].DownwardAPI.Items, api.DownwardAPIVolumeFile{
Path: "annotations",
FieldRef: api.ObjectFieldSelector{
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.annotations",
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment