mirror of https://github.com/k3s-io/k3s
Merge pull request #39341 from smarterclayton/termination_log
Automatic merge from submit-queue Improve TerminationMessagePath to be more flexible * Support `terminationMessagePolicy: fallbackToLogsOnError` which allows pod authors to get useful information from containers as per kubernetes/community#154 * Set an upper bound on the size of the termination message path or log output to prevent callers from DoSing the master * Add tests for running as root, non-root, and for the new terminationMessagePolicy cases. I set the limit to 4096 bytes, but this may be too high for large pod containers. Probably need to set an absolute bound, i.e. max message size allowed is 20k total, and we truncate if we're above that limit. Fixes #31839, #23569 ```release-note A new field `terminationMessagePolicy` has been added to containers that allows a user to request `FallbackToLogsOnError`, which will read from the container's logs to populate the termination message if the user does not write to the termination message log file. The termination message file is now properly readable for end users and has a maximum size (4k bytes) to prevent abuse. Each pod may have up to 12k bytes of termination messages before the contents of each will be truncated. ```pull/6/head
commit
fce60637ae
|
@ -128,6 +128,10 @@
|
|||
"Comment": "v0.8.1-6-gab50d12",
|
||||
"Rev": "ab50d12e88f57788bf84b83fef2be236eb1fcc0b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/armon/circbuf",
|
||||
"Rev": "bbbad097214e2918d8543d5201d12bfd7bca254d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/asaskevich/govalidator",
|
||||
"Comment": "v4-12-g593d645",
|
||||
|
|
|
@ -1546,6 +1546,34 @@ Apache License
|
|||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/armon/circbuf licensed under: =
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Armon Dadgar
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
= vendor/github.com/armon/circbuf/LICENSE d2d77030c0183e3d1e66d26dc1f243be -
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/asaskevich/govalidator licensed under: =
|
||||
|
||||
|
|
|
@ -35061,7 +35061,11 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"terminationMessagePath": {
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.",
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.",
|
||||
"type": "string"
|
||||
},
|
||||
"terminationMessagePolicy": {
|
||||
"description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.",
|
||||
"type": "string"
|
||||
},
|
||||
"tty": {
|
||||
|
|
|
@ -2191,7 +2191,11 @@
|
|||
},
|
||||
"terminationMessagePath": {
|
||||
"type": "string",
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated."
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated."
|
||||
},
|
||||
"terminationMessagePolicy": {
|
||||
"type": "string",
|
||||
"description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated."
|
||||
},
|
||||
"imagePullPolicy": {
|
||||
"type": "string",
|
||||
|
|
|
@ -2196,7 +2196,11 @@
|
|||
},
|
||||
"terminationMessagePath": {
|
||||
"type": "string",
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated."
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated."
|
||||
},
|
||||
"terminationMessagePolicy": {
|
||||
"type": "string",
|
||||
"description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated."
|
||||
},
|
||||
"imagePullPolicy": {
|
||||
"type": "string",
|
||||
|
|
|
@ -8568,7 +8568,11 @@
|
|||
},
|
||||
"terminationMessagePath": {
|
||||
"type": "string",
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated."
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated."
|
||||
},
|
||||
"terminationMessagePolicy": {
|
||||
"type": "string",
|
||||
"description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated."
|
||||
},
|
||||
"imagePullPolicy": {
|
||||
"type": "string",
|
||||
|
|
|
@ -18660,7 +18660,11 @@
|
|||
},
|
||||
"terminationMessagePath": {
|
||||
"type": "string",
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated."
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated."
|
||||
},
|
||||
"terminationMessagePolicy": {
|
||||
"type": "string",
|
||||
"description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated."
|
||||
},
|
||||
"imagePullPolicy": {
|
||||
"type": "string",
|
||||
|
|
|
@ -1803,7 +1803,14 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">terminationMessagePath</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.</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">terminationMessagePolicy</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.</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>
|
||||
|
@ -5011,7 +5018,7 @@ Examples:<br>
|
|||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2017-01-19 19:02:01 UTC
|
||||
Last updated 2017-01-20 19:58:01 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -1707,7 +1707,14 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">terminationMessagePath</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.</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">terminationMessagePolicy</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.</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>
|
||||
|
@ -4943,7 +4950,7 @@ Examples:<br>
|
|||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2017-01-19 19:02:17 UTC
|
||||
Last updated 2017-01-20 19:58:30 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -5765,7 +5765,14 @@ Both these may change in the future. Incoming requests are matched against the h
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">terminationMessagePath</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.</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">terminationMessagePolicy</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.</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>
|
||||
|
@ -7560,7 +7567,7 @@ Both these may change in the future. Incoming requests are matched against the h
|
|||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2017-01-19 19:02:29 UTC
|
||||
Last updated 2017-01-20 19:59:01 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -6380,7 +6380,14 @@ Examples:<br>
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">terminationMessagePath</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.</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">terminationMessagePolicy</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.</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>
|
||||
|
@ -9187,7 +9194,7 @@ Examples:<br>
|
|||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2017-01-19 19:01:55 UTC
|
||||
Last updated 2017-01-20 19:57:54 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -10895,7 +10895,11 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"terminationMessagePath": {
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.",
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.",
|
||||
"type": "string"
|
||||
},
|
||||
"terminationMessagePolicy": {
|
||||
"description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.",
|
||||
"type": "string"
|
||||
},
|
||||
"tty": {
|
||||
|
|
|
@ -5474,7 +5474,11 @@
|
|||
},
|
||||
"terminationMessagePath": {
|
||||
"type": "string",
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated."
|
||||
"description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated."
|
||||
},
|
||||
"terminationMessagePolicy": {
|
||||
"type": "string",
|
||||
"description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated."
|
||||
},
|
||||
"imagePullPolicy": {
|
||||
"type": "string",
|
||||
|
|
|
@ -4923,7 +4923,14 @@ Both these may change in the future. Incoming requests are matched against the h
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">terminationMessagePath</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: Path at which the file to which the container’s termination message will be written is mounted into the container’s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.</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">terminationMessagePolicy</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.</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>
|
||||
|
@ -6263,7 +6270,7 @@ Both these may change in the future. Incoming requests are matched against the h
|
|||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2017-01-06 18:15:24 UTC
|
||||
Last updated 2017-01-17 18:39:44 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -289,6 +289,7 @@ pkg/util/replicaset
|
|||
pkg/util/restoptions
|
||||
pkg/util/runtime
|
||||
pkg/util/sets
|
||||
pkg/util/tail
|
||||
pkg/util/validation
|
||||
pkg/util/validation/field
|
||||
pkg/util/version
|
||||
|
|
|
@ -358,6 +358,7 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
|||
func(ct *api.Container, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(ct) // fuzz self without calling this function again
|
||||
ct.TerminationMessagePath = "/" + ct.TerminationMessagePath // Must be non-empty
|
||||
ct.TerminationMessagePolicy = "File"
|
||||
},
|
||||
func(p *api.Probe, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(p)
|
||||
|
|
|
@ -1257,6 +1257,19 @@ const (
|
|||
PullIfNotPresent PullPolicy = "IfNotPresent"
|
||||
)
|
||||
|
||||
// TerminationMessagePolicy describes how termination messages are retrieved from a container.
|
||||
type TerminationMessagePolicy string
|
||||
|
||||
const (
|
||||
// TerminationMessageReadFile is the default behavior and will set the container status message to
|
||||
// the contents of the container's terminationMessagePath when the container exits.
|
||||
TerminationMessageReadFile TerminationMessagePolicy = "File"
|
||||
// TerminationMessageFallbackToLogsOnError will read the most recent contents of the container logs
|
||||
// for the container status message when the container exits with an error and the
|
||||
// terminationMessagePath has no contents.
|
||||
TerminationMessageFallbackToLogsOnError TerminationMessagePolicy = "FallbackToLogsOnError"
|
||||
)
|
||||
|
||||
// Capability represent POSIX capabilities type
|
||||
type Capability string
|
||||
|
||||
|
@ -1332,6 +1345,8 @@ type Container struct {
|
|||
// Required.
|
||||
// +optional
|
||||
TerminationMessagePath string
|
||||
// +optional
|
||||
TerminationMessagePolicy TerminationMessagePolicy
|
||||
// Required: Policy for pulling images for this container
|
||||
ImagePullPolicy PullPolicy
|
||||
// Optional: SecurityContext defines the security options the container should be run with.
|
||||
|
|
|
@ -121,6 +121,9 @@ func SetDefaults_Container(obj *Container) {
|
|||
if obj.TerminationMessagePath == "" {
|
||||
obj.TerminationMessagePath = TerminationMessagePathDefault
|
||||
}
|
||||
if obj.TerminationMessagePolicy == "" {
|
||||
obj.TerminationMessagePolicy = TerminationMessageReadFile
|
||||
}
|
||||
}
|
||||
func SetDefaults_ServiceSpec(obj *ServiceSpec) {
|
||||
if obj.SessionAffinity == "" {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -426,11 +426,23 @@ message Container {
|
|||
// Optional: Path at which the file to which the container's termination message
|
||||
// will be written is mounted into the container's filesystem.
|
||||
// Message written is intended to be brief final status, such as an assertion failure message.
|
||||
// Will be truncated by the node if greater than 4096 bytes. The total message length across
|
||||
// all containers will be limited to 12kb.
|
||||
// Defaults to /dev/termination-log.
|
||||
// Cannot be updated.
|
||||
// +optional
|
||||
optional string terminationMessagePath = 13;
|
||||
|
||||
// Indicate how the termination message should be populated. File will use the contents of
|
||||
// terminationMessagePath to populate the container status message on both success and failure.
|
||||
// FallbackToLogsOnError will use the last chunk of container log output if the termination
|
||||
// message file is empty and the container exited with an error.
|
||||
// The log output is limited to 2048 bytes or 80 lines, whichever is smaller.
|
||||
// Defaults to File.
|
||||
// Cannot be updated.
|
||||
// +optional
|
||||
optional string terminationMessagePolicy = 20;
|
||||
|
||||
// Image pull policy.
|
||||
// One of Always, Never, IfNotPresent.
|
||||
// Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.
|
||||
|
|
|
@ -22190,6 +22190,32 @@ func (x *PullPolicy) CodecDecodeSelf(d *codec1978.Decoder) {
|
|||
}
|
||||
}
|
||||
|
||||
func (x TerminationMessagePolicy) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.EncBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x) {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x))
|
||||
}
|
||||
}
|
||||
|
||||
func (x *TerminationMessagePolicy) CodecDecodeSelf(d *codec1978.Decoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
yym1 := z.DecBinary()
|
||||
_ = yym1
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x) {
|
||||
} else {
|
||||
*((*string)(x)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
|
||||
func (x Capability) CodecEncodeSelf(e *codec1978.Encoder) {
|
||||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperEncoder(e)
|
||||
|
@ -22704,7 +22730,7 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
} else {
|
||||
yysep2 := !z.EncBinary()
|
||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||
var yyq2 [19]bool
|
||||
var yyq2 [20]bool
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[1] = x.Image != ""
|
||||
|
@ -22720,14 +22746,15 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
yyq2[11] = x.ReadinessProbe != nil
|
||||
yyq2[12] = x.Lifecycle != nil
|
||||
yyq2[13] = x.TerminationMessagePath != ""
|
||||
yyq2[14] = x.ImagePullPolicy != ""
|
||||
yyq2[15] = x.SecurityContext != nil
|
||||
yyq2[16] = x.Stdin != false
|
||||
yyq2[17] = x.StdinOnce != false
|
||||
yyq2[18] = x.TTY != false
|
||||
yyq2[14] = x.TerminationMessagePolicy != ""
|
||||
yyq2[15] = x.ImagePullPolicy != ""
|
||||
yyq2[16] = x.SecurityContext != nil
|
||||
yyq2[17] = x.Stdin != false
|
||||
yyq2[18] = x.StdinOnce != false
|
||||
yyq2[19] = x.TTY != false
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(19)
|
||||
r.EncodeArrayStart(20)
|
||||
} else {
|
||||
yynn2 = 1
|
||||
for _, b := range yyq2 {
|
||||
|
@ -23119,12 +23146,27 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[14] {
|
||||
x.ImagePullPolicy.CodecEncodeSelf(e)
|
||||
x.TerminationMessagePolicy.CodecEncodeSelf(e)
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[14] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("terminationMessagePolicy"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
x.TerminationMessagePolicy.CodecEncodeSelf(e)
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[15] {
|
||||
x.ImagePullPolicy.CodecEncodeSelf(e)
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[15] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("imagePullPolicy"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
|
@ -23133,7 +23175,7 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[15] {
|
||||
if yyq2[16] {
|
||||
if x.SecurityContext == nil {
|
||||
r.EncodeNil()
|
||||
} else {
|
||||
|
@ -23143,7 +23185,7 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
r.EncodeNil()
|
||||
}
|
||||
} else {
|
||||
if yyq2[15] {
|
||||
if yyq2[16] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("securityContext"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
|
@ -23154,31 +23196,6 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[16] {
|
||||
yym54 := z.EncBinary()
|
||||
_ = yym54
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeBool(bool(x.Stdin))
|
||||
}
|
||||
} else {
|
||||
r.EncodeBool(false)
|
||||
}
|
||||
} else {
|
||||
if yyq2[16] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("stdin"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym55 := z.EncBinary()
|
||||
_ = yym55
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeBool(bool(x.Stdin))
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[17] {
|
||||
|
@ -23186,7 +23203,7 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
_ = yym57
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeBool(bool(x.StdinOnce))
|
||||
r.EncodeBool(bool(x.Stdin))
|
||||
}
|
||||
} else {
|
||||
r.EncodeBool(false)
|
||||
|
@ -23194,13 +23211,13 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
} else {
|
||||
if yyq2[17] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("stdinOnce"))
|
||||
r.EncodeString(codecSelferC_UTF81234, string("stdin"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym58 := z.EncBinary()
|
||||
_ = yym58
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeBool(bool(x.StdinOnce))
|
||||
r.EncodeBool(bool(x.Stdin))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23211,7 +23228,7 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
_ = yym60
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeBool(bool(x.TTY))
|
||||
r.EncodeBool(bool(x.StdinOnce))
|
||||
}
|
||||
} else {
|
||||
r.EncodeBool(false)
|
||||
|
@ -23219,11 +23236,36 @@ func (x *Container) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
} else {
|
||||
if yyq2[18] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("tty"))
|
||||
r.EncodeString(codecSelferC_UTF81234, string("stdinOnce"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym61 := z.EncBinary()
|
||||
_ = yym61
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeBool(bool(x.StdinOnce))
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[19] {
|
||||
yym63 := z.EncBinary()
|
||||
_ = yym63
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeBool(bool(x.TTY))
|
||||
}
|
||||
} else {
|
||||
r.EncodeBool(false)
|
||||
}
|
||||
} else {
|
||||
if yyq2[19] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("tty"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym64 := z.EncBinary()
|
||||
_ = yym64
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeBool(bool(x.TTY))
|
||||
}
|
||||
|
@ -23450,12 +23492,19 @@ func (x *Container) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
|||
*((*string)(yyv26)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
case "terminationMessagePolicy":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.TerminationMessagePolicy = ""
|
||||
} else {
|
||||
yyv28 := &x.TerminationMessagePolicy
|
||||
yyv28.CodecDecodeSelf(d)
|
||||
}
|
||||
case "imagePullPolicy":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.ImagePullPolicy = ""
|
||||
} else {
|
||||
yyv28 := &x.ImagePullPolicy
|
||||
yyv28.CodecDecodeSelf(d)
|
||||
yyv29 := &x.ImagePullPolicy
|
||||
yyv29.CodecDecodeSelf(d)
|
||||
}
|
||||
case "securityContext":
|
||||
if r.TryDecodeAsNil() {
|
||||
|
@ -23472,36 +23521,36 @@ func (x *Container) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Stdin = false
|
||||
} else {
|
||||
yyv30 := &x.Stdin
|
||||
yym31 := z.DecBinary()
|
||||
_ = yym31
|
||||
yyv31 := &x.Stdin
|
||||
yym32 := z.DecBinary()
|
||||
_ = yym32
|
||||
if false {
|
||||
} else {
|
||||
*((*bool)(yyv30)) = r.DecodeBool()
|
||||
*((*bool)(yyv31)) = r.DecodeBool()
|
||||
}
|
||||
}
|
||||
case "stdinOnce":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.StdinOnce = false
|
||||
} else {
|
||||
yyv32 := &x.StdinOnce
|
||||
yym33 := z.DecBinary()
|
||||
_ = yym33
|
||||
yyv33 := &x.StdinOnce
|
||||
yym34 := z.DecBinary()
|
||||
_ = yym34
|
||||
if false {
|
||||
} else {
|
||||
*((*bool)(yyv32)) = r.DecodeBool()
|
||||
*((*bool)(yyv33)) = r.DecodeBool()
|
||||
}
|
||||
}
|
||||
case "tty":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.TTY = false
|
||||
} else {
|
||||
yyv34 := &x.TTY
|
||||
yym35 := z.DecBinary()
|
||||
_ = yym35
|
||||
yyv35 := &x.TTY
|
||||
yym36 := z.DecBinary()
|
||||
_ = yym36
|
||||
if false {
|
||||
} else {
|
||||
*((*bool)(yyv34)) = r.DecodeBool()
|
||||
*((*bool)(yyv35)) = r.DecodeBool()
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
@ -23515,16 +23564,16 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yyj36 int
|
||||
var yyb36 bool
|
||||
var yyhl36 bool = l >= 0
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
var yyj37 int
|
||||
var yyb37 bool
|
||||
var yyhl37 bool = l >= 0
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23532,21 +23581,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Name = ""
|
||||
} else {
|
||||
yyv37 := &x.Name
|
||||
yym38 := z.DecBinary()
|
||||
_ = yym38
|
||||
yyv38 := &x.Name
|
||||
yym39 := z.DecBinary()
|
||||
_ = yym39
|
||||
if false {
|
||||
} else {
|
||||
*((*string)(yyv37)) = r.DecodeString()
|
||||
*((*string)(yyv38)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23554,21 +23603,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Image = ""
|
||||
} else {
|
||||
yyv39 := &x.Image
|
||||
yym40 := z.DecBinary()
|
||||
_ = yym40
|
||||
yyv40 := &x.Image
|
||||
yym41 := z.DecBinary()
|
||||
_ = yym41
|
||||
if false {
|
||||
} else {
|
||||
*((*string)(yyv39)) = r.DecodeString()
|
||||
*((*string)(yyv40)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23576,21 +23625,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Command = nil
|
||||
} else {
|
||||
yyv41 := &x.Command
|
||||
yym42 := z.DecBinary()
|
||||
_ = yym42
|
||||
yyv42 := &x.Command
|
||||
yym43 := z.DecBinary()
|
||||
_ = yym43
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecSliceStringX(yyv41, false, d)
|
||||
z.F.DecSliceStringX(yyv42, false, d)
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23598,21 +23647,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Args = nil
|
||||
} else {
|
||||
yyv43 := &x.Args
|
||||
yym44 := z.DecBinary()
|
||||
_ = yym44
|
||||
yyv44 := &x.Args
|
||||
yym45 := z.DecBinary()
|
||||
_ = yym45
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecSliceStringX(yyv43, false, d)
|
||||
z.F.DecSliceStringX(yyv44, false, d)
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23620,21 +23669,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.WorkingDir = ""
|
||||
} else {
|
||||
yyv45 := &x.WorkingDir
|
||||
yym46 := z.DecBinary()
|
||||
_ = yym46
|
||||
yyv46 := &x.WorkingDir
|
||||
yym47 := z.DecBinary()
|
||||
_ = yym47
|
||||
if false {
|
||||
} else {
|
||||
*((*string)(yyv45)) = r.DecodeString()
|
||||
*((*string)(yyv46)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23642,21 +23691,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Ports = nil
|
||||
} else {
|
||||
yyv47 := &x.Ports
|
||||
yym48 := z.DecBinary()
|
||||
_ = yym48
|
||||
yyv48 := &x.Ports
|
||||
yym49 := z.DecBinary()
|
||||
_ = yym49
|
||||
if false {
|
||||
} else {
|
||||
h.decSliceContainerPort((*[]ContainerPort)(yyv47), d)
|
||||
h.decSliceContainerPort((*[]ContainerPort)(yyv48), d)
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23664,21 +23713,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.EnvFrom = nil
|
||||
} else {
|
||||
yyv49 := &x.EnvFrom
|
||||
yym50 := z.DecBinary()
|
||||
_ = yym50
|
||||
yyv50 := &x.EnvFrom
|
||||
yym51 := z.DecBinary()
|
||||
_ = yym51
|
||||
if false {
|
||||
} else {
|
||||
h.decSliceEnvFromSource((*[]EnvFromSource)(yyv49), d)
|
||||
h.decSliceEnvFromSource((*[]EnvFromSource)(yyv50), d)
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23686,21 +23735,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Env = nil
|
||||
} else {
|
||||
yyv51 := &x.Env
|
||||
yym52 := z.DecBinary()
|
||||
_ = yym52
|
||||
yyv52 := &x.Env
|
||||
yym53 := z.DecBinary()
|
||||
_ = yym53
|
||||
if false {
|
||||
} else {
|
||||
h.decSliceEnvVar((*[]EnvVar)(yyv51), d)
|
||||
h.decSliceEnvVar((*[]EnvVar)(yyv52), d)
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23708,16 +23757,16 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Resources = ResourceRequirements{}
|
||||
} else {
|
||||
yyv53 := &x.Resources
|
||||
yyv53.CodecDecodeSelf(d)
|
||||
yyv54 := &x.Resources
|
||||
yyv54.CodecDecodeSelf(d)
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23725,21 +23774,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.VolumeMounts = nil
|
||||
} else {
|
||||
yyv54 := &x.VolumeMounts
|
||||
yym55 := z.DecBinary()
|
||||
_ = yym55
|
||||
yyv55 := &x.VolumeMounts
|
||||
yym56 := z.DecBinary()
|
||||
_ = yym56
|
||||
if false {
|
||||
} else {
|
||||
h.decSliceVolumeMount((*[]VolumeMount)(yyv54), d)
|
||||
h.decSliceVolumeMount((*[]VolumeMount)(yyv55), d)
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23754,13 +23803,13 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
}
|
||||
x.LivenessProbe.CodecDecodeSelf(d)
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23775,13 +23824,13 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
}
|
||||
x.ReadinessProbe.CodecDecodeSelf(d)
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23796,13 +23845,13 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
}
|
||||
x.Lifecycle.CodecDecodeSelf(d)
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23810,21 +23859,38 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.TerminationMessagePath = ""
|
||||
} else {
|
||||
yyv59 := &x.TerminationMessagePath
|
||||
yym60 := z.DecBinary()
|
||||
_ = yym60
|
||||
yyv60 := &x.TerminationMessagePath
|
||||
yym61 := z.DecBinary()
|
||||
_ = yym61
|
||||
if false {
|
||||
} else {
|
||||
*((*string)(yyv59)) = r.DecodeString()
|
||||
*((*string)(yyv60)) = r.DecodeString()
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.TerminationMessagePolicy = ""
|
||||
} else {
|
||||
yyv62 := &x.TerminationMessagePolicy
|
||||
yyv62.CodecDecodeSelf(d)
|
||||
}
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23832,16 +23898,16 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.ImagePullPolicy = ""
|
||||
} else {
|
||||
yyv61 := &x.ImagePullPolicy
|
||||
yyv61.CodecDecodeSelf(d)
|
||||
yyv63 := &x.ImagePullPolicy
|
||||
yyv63.CodecDecodeSelf(d)
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23856,13 +23922,13 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
}
|
||||
x.SecurityContext.CodecDecodeSelf(d)
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -23870,29 +23936,7 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Stdin = false
|
||||
} else {
|
||||
yyv63 := &x.Stdin
|
||||
yym64 := z.DecBinary()
|
||||
_ = yym64
|
||||
if false {
|
||||
} else {
|
||||
*((*bool)(yyv63)) = r.DecodeBool()
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.StdinOnce = false
|
||||
} else {
|
||||
yyv65 := &x.StdinOnce
|
||||
yyv65 := &x.Stdin
|
||||
yym66 := z.DecBinary()
|
||||
_ = yym66
|
||||
if false {
|
||||
|
@ -23900,21 +23944,21 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
*((*bool)(yyv65)) = r.DecodeBool()
|
||||
}
|
||||
}
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb36 {
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.TTY = false
|
||||
x.StdinOnce = false
|
||||
} else {
|
||||
yyv67 := &x.TTY
|
||||
yyv67 := &x.StdinOnce
|
||||
yym68 := z.DecBinary()
|
||||
_ = yym68
|
||||
if false {
|
||||
|
@ -23922,18 +23966,40 @@ func (x *Container) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
*((*bool)(yyv67)) = r.DecodeBool()
|
||||
}
|
||||
}
|
||||
for {
|
||||
yyj36++
|
||||
if yyhl36 {
|
||||
yyb36 = yyj36 > l
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb37 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.TTY = false
|
||||
} else {
|
||||
yyv69 := &x.TTY
|
||||
yym70 := z.DecBinary()
|
||||
_ = yym70
|
||||
if false {
|
||||
} else {
|
||||
yyb36 = r.CheckBreak()
|
||||
*((*bool)(yyv69)) = r.DecodeBool()
|
||||
}
|
||||
if yyb36 {
|
||||
}
|
||||
for {
|
||||
yyj37++
|
||||
if yyhl37 {
|
||||
yyb37 = yyj37 > l
|
||||
} else {
|
||||
yyb37 = r.CheckBreak()
|
||||
}
|
||||
if yyb37 {
|
||||
break
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
z.DecStructFieldNotFound(yyj36-1, "")
|
||||
z.DecStructFieldNotFound(yyj37-1, "")
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
|
@ -64355,7 +64421,7 @@ func (x codecSelfer1234) decSliceContainer(v *[]Container, d *codec1978.Decoder)
|
|||
|
||||
yyrg1 := len(yyv1) > 0
|
||||
yyv21 := yyv1
|
||||
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 280)
|
||||
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 296)
|
||||
if yyrt1 {
|
||||
if yyrl1 <= cap(yyv1) {
|
||||
yyv1 = yyv1[:yyrl1]
|
||||
|
|
|
@ -1367,6 +1367,19 @@ const (
|
|||
PullIfNotPresent PullPolicy = "IfNotPresent"
|
||||
)
|
||||
|
||||
// TerminationMessagePolicy describes how termination messages are retrieved from a container.
|
||||
type TerminationMessagePolicy string
|
||||
|
||||
const (
|
||||
// TerminationMessageReadFile is the default behavior and will set the container status message to
|
||||
// the contents of the container's terminationMessagePath when the container exits.
|
||||
TerminationMessageReadFile TerminationMessagePolicy = "File"
|
||||
// TerminationMessageFallbackToLogsOnError will read the most recent contents of the container logs
|
||||
// for the container status message when the container exits with an error and the
|
||||
// terminationMessagePath has no contents.
|
||||
TerminationMessageFallbackToLogsOnError TerminationMessagePolicy = "FallbackToLogsOnError"
|
||||
)
|
||||
|
||||
// Capability represent POSIX capabilities type
|
||||
type Capability string
|
||||
|
||||
|
@ -1484,10 +1497,21 @@ type Container struct {
|
|||
// Optional: Path at which the file to which the container's termination message
|
||||
// will be written is mounted into the container's filesystem.
|
||||
// Message written is intended to be brief final status, such as an assertion failure message.
|
||||
// Will be truncated by the node if greater than 4096 bytes. The total message length across
|
||||
// all containers will be limited to 12kb.
|
||||
// Defaults to /dev/termination-log.
|
||||
// Cannot be updated.
|
||||
// +optional
|
||||
TerminationMessagePath string `json:"terminationMessagePath,omitempty" protobuf:"bytes,13,opt,name=terminationMessagePath"`
|
||||
// Indicate how the termination message should be populated. File will use the contents of
|
||||
// terminationMessagePath to populate the container status message on both success and failure.
|
||||
// FallbackToLogsOnError will use the last chunk of container log output if the termination
|
||||
// message file is empty and the container exited with an error.
|
||||
// The log output is limited to 2048 bytes or 80 lines, whichever is smaller.
|
||||
// Defaults to File.
|
||||
// Cannot be updated.
|
||||
// +optional
|
||||
TerminationMessagePolicy TerminationMessagePolicy `json:"terminationMessagePolicy,omitempty" protobuf:"bytes,20,opt,name=terminationMessagePolicy,casttype=TerminationMessagePolicy"`
|
||||
// Image pull policy.
|
||||
// One of Always, Never, IfNotPresent.
|
||||
// Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.
|
||||
|
|
|
@ -218,26 +218,27 @@ func (ConfigMapVolumeSource) SwaggerDoc() map[string]string {
|
|||
}
|
||||
|
||||
var map_Container = map[string]string{
|
||||
"": "A single application container that you want to run within a pod.",
|
||||
"name": "Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique name (DNS_LABEL). Cannot be updated.",
|
||||
"image": "Docker image name. More info: http://kubernetes.io/docs/user-guide/images",
|
||||
"command": "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/containers#containers-and-commands",
|
||||
"args": "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/containers#containers-and-commands",
|
||||
"workingDir": "Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated.",
|
||||
"ports": "List of ports to expose from the container. Exposing a port here gives the system additional information about the network connections a container uses, but is primarily informational. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default \"0.0.0.0\" address inside a container will be accessible from the network. Cannot be updated.",
|
||||
"envFrom": "List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. An invalid key will prevent the container from starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated.",
|
||||
"env": "List of environment variables to set in the container. Cannot be updated.",
|
||||
"resources": "Compute Resources required by this container. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/persistent-volumes#resources",
|
||||
"volumeMounts": "Pod volumes to mount into the container's filesystem. Cannot be updated.",
|
||||
"livenessProbe": "Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/pod-states#container-probes",
|
||||
"readinessProbe": "Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/pod-states#container-probes",
|
||||
"lifecycle": "Actions that the management system should take in response to container lifecycle events. Cannot be updated.",
|
||||
"terminationMessagePath": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.",
|
||||
"imagePullPolicy": "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/images#updating-images",
|
||||
"securityContext": "Security options the pod should run with. More info: http://releases.k8s.io/HEAD/docs/design/security_context.md",
|
||||
"stdin": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false.",
|
||||
"stdinOnce": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false",
|
||||
"tty": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false.",
|
||||
"": "A single application container that you want to run within a pod.",
|
||||
"name": "Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique name (DNS_LABEL). Cannot be updated.",
|
||||
"image": "Docker image name. More info: http://kubernetes.io/docs/user-guide/images",
|
||||
"command": "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/containers#containers-and-commands",
|
||||
"args": "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/containers#containers-and-commands",
|
||||
"workingDir": "Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated.",
|
||||
"ports": "List of ports to expose from the container. Exposing a port here gives the system additional information about the network connections a container uses, but is primarily informational. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default \"0.0.0.0\" address inside a container will be accessible from the network. Cannot be updated.",
|
||||
"envFrom": "List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. An invalid key will prevent the container from starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated.",
|
||||
"env": "List of environment variables to set in the container. Cannot be updated.",
|
||||
"resources": "Compute Resources required by this container. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/persistent-volumes#resources",
|
||||
"volumeMounts": "Pod volumes to mount into the container's filesystem. Cannot be updated.",
|
||||
"livenessProbe": "Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/pod-states#container-probes",
|
||||
"readinessProbe": "Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/pod-states#container-probes",
|
||||
"lifecycle": "Actions that the management system should take in response to container lifecycle events. Cannot be updated.",
|
||||
"terminationMessagePath": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.",
|
||||
"terminationMessagePolicy": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.",
|
||||
"imagePullPolicy": "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/images#updating-images",
|
||||
"securityContext": "Security options the pod should run with. More info: http://releases.k8s.io/HEAD/docs/design/security_context.md",
|
||||
"stdin": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false.",
|
||||
"stdinOnce": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false",
|
||||
"tty": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false.",
|
||||
}
|
||||
|
||||
func (Container) SwaggerDoc() map[string]string {
|
||||
|
|
|
@ -779,6 +779,7 @@ func autoConvert_v1_Container_To_api_Container(in *Container, out *api.Container
|
|||
out.ReadinessProbe = (*api.Probe)(unsafe.Pointer(in.ReadinessProbe))
|
||||
out.Lifecycle = (*api.Lifecycle)(unsafe.Pointer(in.Lifecycle))
|
||||
out.TerminationMessagePath = in.TerminationMessagePath
|
||||
out.TerminationMessagePolicy = api.TerminationMessagePolicy(in.TerminationMessagePolicy)
|
||||
out.ImagePullPolicy = api.PullPolicy(in.ImagePullPolicy)
|
||||
out.SecurityContext = (*api.SecurityContext)(unsafe.Pointer(in.SecurityContext))
|
||||
out.Stdin = in.Stdin
|
||||
|
@ -808,6 +809,7 @@ func autoConvert_api_Container_To_v1_Container(in *api.Container, out *Container
|
|||
out.ReadinessProbe = (*Probe)(unsafe.Pointer(in.ReadinessProbe))
|
||||
out.Lifecycle = (*Lifecycle)(unsafe.Pointer(in.Lifecycle))
|
||||
out.TerminationMessagePath = in.TerminationMessagePath
|
||||
out.TerminationMessagePolicy = TerminationMessagePolicy(in.TerminationMessagePolicy)
|
||||
out.ImagePullPolicy = PullPolicy(in.ImagePullPolicy)
|
||||
out.SecurityContext = (*SecurityContext)(unsafe.Pointer(in.SecurityContext))
|
||||
out.Stdin = in.Stdin
|
||||
|
|
|
@ -1597,6 +1597,14 @@ func validateContainers(containers []api.Container, volumes sets.String, fldPath
|
|||
allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe", "successThreshold"), ctr.LivenessProbe.SuccessThreshold, "must be 1"))
|
||||
}
|
||||
|
||||
switch ctr.TerminationMessagePolicy {
|
||||
case api.TerminationMessageReadFile, api.TerminationMessageFallbackToLogsOnError:
|
||||
case "":
|
||||
allErrs = append(allErrs, field.Required(idxPath.Child("terminationMessagePolicy"), "must be 'File' or 'FallbackToLogsOnError'"))
|
||||
default:
|
||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("terminationMessagePolicy"), ctr.TerminationMessagePolicy, "must be 'File' or 'FallbackToLogsOnError'"))
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, idxPath.Child("readinessProbe"))...)
|
||||
allErrs = append(allErrs, validateContainerPorts(ctr.Ports, idxPath.Child("ports"))...)
|
||||
allErrs = append(allErrs, validateEnv(ctr.Env, idxPath.Child("env"))...)
|
||||
|
|
|
@ -2484,11 +2484,11 @@ func TestValidatePullPolicy(t *testing.T) {
|
|||
}
|
||||
testCases := map[string]T{
|
||||
"NotPresent1": {
|
||||
api.Container{Name: "abc", Image: "image:latest", ImagePullPolicy: "IfNotPresent"},
|
||||
api.Container{Name: "abc", Image: "image:latest", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
api.PullIfNotPresent,
|
||||
},
|
||||
"NotPresent2": {
|
||||
api.Container{Name: "abc1", Image: "image", ImagePullPolicy: "IfNotPresent"},
|
||||
api.Container{Name: "abc1", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
api.PullIfNotPresent,
|
||||
},
|
||||
"Always1": {
|
||||
|
@ -2534,9 +2534,9 @@ func TestValidateContainers(t *testing.T) {
|
|||
})
|
||||
|
||||
successCase := []api.Container{
|
||||
{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"},
|
||||
{Name: "123", Image: "image", ImagePullPolicy: "IfNotPresent"},
|
||||
{Name: "abc-123", Image: "image", ImagePullPolicy: "IfNotPresent"},
|
||||
{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
{Name: "123", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
{Name: "abc-123", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
{
|
||||
Name: "life-123",
|
||||
Image: "image",
|
||||
|
@ -2545,7 +2545,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
Exec: &api.ExecAction{Command: []string{"ls", "-l"}},
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{
|
||||
Name: "resources-test",
|
||||
|
@ -2557,7 +2558,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
api.ResourceName("my.org/resource"): resource.MustParse("10m"),
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{
|
||||
Name: "resources-test-with-gpu-with-request",
|
||||
|
@ -2574,7 +2576,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
api.ResourceName(api.ResourceNvidiaGPU): resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{
|
||||
Name: "resources-test-with-gpu-without-request",
|
||||
|
@ -2590,7 +2593,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
api.ResourceName(api.ResourceNvidiaGPU): resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{
|
||||
Name: "resources-request-limit-simple",
|
||||
|
@ -2603,7 +2607,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{
|
||||
Name: "resources-request-limit-edge",
|
||||
|
@ -2620,7 +2625,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
api.ResourceName("my.org/resource"): resource.MustParse("10m"),
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{
|
||||
Name: "resources-request-limit-partials",
|
||||
|
@ -2635,7 +2641,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
api.ResourceName("my.org/resource"): resource.MustParse("10m"),
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{
|
||||
Name: "resources-request",
|
||||
|
@ -2646,7 +2653,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{
|
||||
Name: "same-host-port-different-protocol",
|
||||
|
@ -2655,9 +2663,22 @@ func TestValidateContainers(t *testing.T) {
|
|||
{ContainerPort: 80, HostPort: 80, Protocol: "TCP"},
|
||||
{ContainerPort: 80, HostPort: 80, Protocol: "UDP"},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", SecurityContext: fakeValidSecurityContext(true)},
|
||||
{
|
||||
Name: "fallback-to-logs-termination-message",
|
||||
Image: "image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "FallbackToLogsOnError",
|
||||
},
|
||||
{
|
||||
Name: "file-termination-message",
|
||||
Image: "image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
{Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", SecurityContext: fakeValidSecurityContext(true)},
|
||||
}
|
||||
if errs := validateContainers(successCase, volumes, field.NewPath("field")); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
|
@ -2667,26 +2688,26 @@ func TestValidateContainers(t *testing.T) {
|
|||
AllowPrivileged: false,
|
||||
})
|
||||
errorCases := map[string][]api.Container{
|
||||
"zero-length name": {{Name: "", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
"name > 63 characters": {{Name: strings.Repeat("a", 64), Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
"name not a DNS label": {{Name: "a.b.c", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
"zero-length name": {{Name: "", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
"name > 63 characters": {{Name: strings.Repeat("a", 64), Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
"name not a DNS label": {{Name: "a.b.c", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
"name not unique": {
|
||||
{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"},
|
||||
{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"},
|
||||
{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
},
|
||||
"zero-length image": {{Name: "abc", Image: "", ImagePullPolicy: "IfNotPresent"}},
|
||||
"zero-length image": {{Name: "abc", Image: "", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
"host port not unique": {
|
||||
{Name: "abc", Image: "image", Ports: []api.ContainerPort{{ContainerPort: 80, HostPort: 80, Protocol: "TCP"}},
|
||||
ImagePullPolicy: "IfNotPresent"},
|
||||
ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
{Name: "def", Image: "image", Ports: []api.ContainerPort{{ContainerPort: 81, HostPort: 80, Protocol: "TCP"}},
|
||||
ImagePullPolicy: "IfNotPresent"},
|
||||
ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
},
|
||||
"invalid env var name": {
|
||||
{Name: "abc", Image: "image", Env: []api.EnvVar{{Name: "ev.1"}}, ImagePullPolicy: "IfNotPresent"},
|
||||
{Name: "abc", Image: "image", Env: []api.EnvVar{{Name: "ev.1"}}, ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
},
|
||||
"unknown volume name": {
|
||||
{Name: "abc", Image: "image", VolumeMounts: []api.VolumeMount{{Name: "anything", MountPath: "/foo"}},
|
||||
ImagePullPolicy: "IfNotPresent"},
|
||||
ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"},
|
||||
},
|
||||
"invalid lifecycle, no exec command.": {
|
||||
{
|
||||
|
@ -2697,7 +2718,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
Exec: &api.ExecAction{},
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"invalid lifecycle, no http path.": {
|
||||
|
@ -2709,7 +2731,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
HTTPGet: &api.HTTPGetAction{},
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"invalid lifecycle, no tcp socket port.": {
|
||||
|
@ -2721,7 +2744,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
TCPSocket: &api.TCPSocketAction{},
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"invalid lifecycle, zero tcp socket port.": {
|
||||
|
@ -2735,7 +2759,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"invalid lifecycle, no action.": {
|
||||
|
@ -2745,7 +2770,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
Lifecycle: &api.Lifecycle{
|
||||
PreStop: &api.Handler{},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"invalid liveness probe, no tcp socket port.": {
|
||||
|
@ -2757,7 +2783,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
TCPSocket: &api.TCPSocketAction{},
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"invalid liveness probe, no action.": {
|
||||
|
@ -2767,7 +2794,24 @@ func TestValidateContainers(t *testing.T) {
|
|||
LivenessProbe: &api.Probe{
|
||||
Handler: api.Handler{},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"invalid message termination policy": {
|
||||
{
|
||||
Name: "life-123",
|
||||
Image: "image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "Unknown",
|
||||
},
|
||||
},
|
||||
"empty message termination policy": {
|
||||
{
|
||||
Name: "life-123",
|
||||
Image: "image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "",
|
||||
},
|
||||
},
|
||||
"privilege disabled": {
|
||||
|
@ -2782,7 +2826,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
"disk": resource.MustParse("10G"),
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"Resource CPU invalid": {
|
||||
|
@ -2792,7 +2837,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
Resources: api.ResourceRequirements{
|
||||
Limits: getResourceLimits("-10", "0"),
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"Resource Requests CPU invalid": {
|
||||
|
@ -2802,7 +2848,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
Resources: api.ResourceRequirements{
|
||||
Requests: getResourceLimits("-10", "0"),
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"Resource Memory invalid": {
|
||||
|
@ -2812,7 +2859,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
Resources: api.ResourceRequirements{
|
||||
Limits: getResourceLimits("0", "-10"),
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"Resource GPU limit must match request": {
|
||||
|
@ -2831,7 +2879,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
api.ResourceName(api.ResourceNvidiaGPU): resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
},
|
||||
},
|
||||
"Request limit simple invalid": {
|
||||
|
@ -2842,7 +2891,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
Limits: getResourceLimits("5", "3"),
|
||||
Requests: getResourceLimits("6", "3"),
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
"Request limit multiple invalid": {
|
||||
|
@ -2853,7 +2903,8 @@ func TestValidateContainers(t *testing.T) {
|
|||
Limits: getResourceLimits("5", "3"),
|
||||
Requests: getResourceLimits("6", "4"),
|
||||
},
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -2908,7 +2959,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
successCases := []api.PodSpec{
|
||||
{ // Populate basic fields, leave defaults for most.
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -2916,8 +2967,8 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
Volumes: []api.Volume{
|
||||
{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
|
||||
},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
InitContainers: []api.Container{{Name: "ictr", Image: "iimage", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
InitContainers: []api.Container{{Name: "ictr", Image: "iimage", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
NodeSelector: map[string]string{
|
||||
"key": "value",
|
||||
|
@ -2929,8 +2980,9 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
},
|
||||
{ // Populate HostNetwork.
|
||||
Containers: []api.Container{
|
||||
{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", Ports: []api.ContainerPort{
|
||||
{HostPort: 8080, ContainerPort: 8080, Protocol: "TCP"}},
|
||||
{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File",
|
||||
Ports: []api.ContainerPort{
|
||||
{HostPort: 8080, ContainerPort: 8080, Protocol: "TCP"}},
|
||||
},
|
||||
},
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
|
@ -2940,7 +2992,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
{ // Populate RunAsUser SupplementalGroups FSGroup with minID 0
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
SupplementalGroups: []int64{minID},
|
||||
RunAsUser: &minID,
|
||||
|
@ -2950,7 +3002,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
{ // Populate RunAsUser SupplementalGroups FSGroup with maxID 2147483647
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
SupplementalGroups: []int64{maxID},
|
||||
RunAsUser: &maxID,
|
||||
|
@ -2964,7 +3016,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
HostIPC: true,
|
||||
},
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -2973,13 +3025,13 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
HostPID: true,
|
||||
},
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
{ // Populate Affinity.
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -2998,7 +3050,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
Volumes: []api.Volume{{}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
"no containers": {
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
|
@ -3010,7 +3062,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
"bad init container": {
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
InitContainers: []api.Container{{}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
|
@ -3018,10 +3070,10 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
"bad DNS policy": {
|
||||
DNSPolicy: api.DNSPolicy("invalid"),
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
"bad service account name": {
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
ServiceAccountName: "invalidName",
|
||||
|
@ -3029,7 +3081,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
"bad restart policy": {
|
||||
RestartPolicy: "UnknowPolicy",
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
"with hostNetwork hostPort not equal to containerPort": {
|
||||
Containers: []api.Container{
|
||||
|
@ -3044,7 +3096,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
"bad supplementalGroups large than math.MaxInt32": {
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
HostNetwork: false,
|
||||
SupplementalGroups: []int64{maxID, 1234},
|
||||
|
@ -3053,7 +3105,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
"bad supplementalGroups less than 0": {
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
HostNetwork: false,
|
||||
SupplementalGroups: []int64{minID, 1234},
|
||||
|
@ -3062,7 +3114,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
"bad runAsUser large than math.MaxInt32": {
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
HostNetwork: false,
|
||||
RunAsUser: &maxID,
|
||||
|
@ -3071,7 +3123,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
"bad runAsUser less than 0": {
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
HostNetwork: false,
|
||||
RunAsUser: &minID,
|
||||
|
@ -3080,7 +3132,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
"bad fsGroup large than math.MaxInt32": {
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
HostNetwork: false,
|
||||
FSGroup: &maxID,
|
||||
|
@ -3089,7 +3141,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
"bad fsGroup less than 0": {
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
HostNetwork: false,
|
||||
FSGroup: &minID,
|
||||
|
@ -3101,7 +3153,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
Volumes: []api.Volume{
|
||||
{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
|
||||
},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
NodeSelector: map[string]string{
|
||||
"key": "value",
|
||||
|
@ -3113,7 +3165,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
"bad nodeName": {
|
||||
NodeName: "node name",
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -3128,7 +3180,7 @@ func TestValidatePodSpec(t *testing.T) {
|
|||
func TestValidatePod(t *testing.T) {
|
||||
validPodSpec := func(affinity *api.Affinity) api.PodSpec {
|
||||
spec := api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
}
|
||||
|
@ -3143,7 +3195,7 @@ func TestValidatePod(t *testing.T) {
|
|||
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -3154,7 +3206,7 @@ func TestValidatePod(t *testing.T) {
|
|||
Volumes: []api.Volume{
|
||||
{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
|
||||
},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
NodeSelector: map[string]string{
|
||||
|
@ -3446,8 +3498,8 @@ func TestValidatePod(t *testing.T) {
|
|||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
InitContainers: []api.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
InitContainers: []api.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -3489,9 +3541,10 @@ func TestValidatePod(t *testing.T) {
|
|||
api.OpaqueIntResourceName("A"): resource.MustParse("20"),
|
||||
},
|
||||
},
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -3499,7 +3552,7 @@ func TestValidatePod(t *testing.T) {
|
|||
{ // valid opaque integer resources for regular container
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "valid-opaque-int", Namespace: "ns"},
|
||||
Spec: api.PodSpec{
|
||||
InitContainers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
InitContainers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "valid-opaque-int",
|
||||
|
@ -3513,6 +3566,7 @@ func TestValidatePod(t *testing.T) {
|
|||
api.OpaqueIntResourceName("A"): resource.MustParse("20"),
|
||||
},
|
||||
},
|
||||
TerminationMessagePolicy: "File",
|
||||
},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
|
@ -3532,7 +3586,7 @@ func TestValidatePod(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
},
|
||||
"bad namespace": {
|
||||
|
@ -3540,7 +3594,7 @@ func TestValidatePod(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
},
|
||||
"bad spec": {
|
||||
|
@ -3560,7 +3614,7 @@ func TestValidatePod(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
},
|
||||
"invalid node selector requirement in node affinity, operator can't be null": {
|
||||
|
@ -3575,7 +3629,6 @@ func TestValidatePod(t *testing.T) {
|
|||
{
|
||||
MatchExpressions: []api.NodeSelectorRequirement{
|
||||
{
|
||||
|
||||
Key: "key1",
|
||||
},
|
||||
},
|
||||
|
@ -3916,8 +3969,8 @@ func TestValidatePod(t *testing.T) {
|
|||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
InitContainers: []api.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
InitContainers: []api.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -4039,7 +4092,7 @@ func TestValidatePod(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -4084,7 +4137,7 @@ func TestValidatePod(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
|
@ -5179,7 +5232,7 @@ func TestValidateReplicationControllerStatusUpdate(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -5262,7 +5315,7 @@ func TestValidateReplicationControllerUpdate(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -5274,7 +5327,7 @@ func TestValidateReplicationControllerUpdate(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
|
||||
},
|
||||
},
|
||||
|
@ -5425,7 +5478,7 @@ func TestValidateReplicationController(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -5438,7 +5491,7 @@ func TestValidateReplicationController(t *testing.T) {
|
|||
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -5582,7 +5635,7 @@ func TestValidateReplicationController(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: validSelector,
|
||||
|
@ -5601,7 +5654,7 @@ func TestValidateReplicationController(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyNever,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: validSelector,
|
||||
|
|
|
@ -40,7 +40,7 @@ func getValidPodTemplateSpecForManual(selector *metav1.LabelSelector) api.PodTem
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ func getValidPodTemplateSpecForGenerated(selector *metav1.LabelSelector) api.Pod
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ func TestValidateJob(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -186,7 +186,7 @@ func TestValidateJob(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -207,7 +207,7 @@ func TestValidateJob(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -518,7 +518,7 @@ func TestValidateCronJob(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -265,25 +265,25 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
|
|||
validPodSpecAbc := api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
}
|
||||
validPodSpecDef := api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
}
|
||||
validPodSpecNodeSelector := api.PodSpec{
|
||||
NodeSelector: validSelector,
|
||||
NodeName: "xyz",
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
}
|
||||
validPodSpecVolume := api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
}
|
||||
|
||||
validPodTemplateAbc := api.PodTemplate{
|
||||
|
@ -514,7 +514,7 @@ func TestValidateDaemonSet(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -642,7 +642,7 @@ func TestValidateDaemonSet(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: validSelector,
|
||||
|
@ -661,7 +661,7 @@ func TestValidateDaemonSet(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyNever,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: validSelector,
|
||||
|
@ -725,9 +725,10 @@ func validDeployment() *extensions.Deployment {
|
|||
DNSPolicy: api.DNSDefault,
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: "image",
|
||||
ImagePullPolicy: api.PullNever,
|
||||
Name: "nginx",
|
||||
Image: "image",
|
||||
ImagePullPolicy: api.PullNever,
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1217,7 +1218,7 @@ func TestValidateReplicaSetStatusUpdate(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1300,7 +1301,7 @@ func TestValidateReplicaSetUpdate(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1312,7 +1313,7 @@ func TestValidateReplicaSetUpdate(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
|
||||
},
|
||||
},
|
||||
|
@ -1463,7 +1464,7 @@ func TestValidateReplicaSet(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1476,7 +1477,7 @@ func TestValidateReplicaSet(t *testing.T) {
|
|||
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1620,7 +1621,7 @@ func TestValidateReplicaSet(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: validLabels,
|
||||
|
@ -1639,7 +1640,7 @@ func TestValidateReplicaSet(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyNever,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: validLabels,
|
||||
|
|
|
@ -1178,7 +1178,14 @@ var OpenAPIDefinitions *openapi.OpenAPIDefinitions = &openapi.OpenAPIDefinitions
|
|||
},
|
||||
"terminationMessagePath": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.",
|
||||
Description: "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"terminationMessagePolicy": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
|
|
|
@ -46,11 +46,12 @@ func TestDecodeSinglePod(t *testing.T) {
|
|||
DNSPolicy: v1.DNSClusterFirst,
|
||||
TerminationGracePeriodSeconds: &grace,
|
||||
Containers: []v1.Container{{
|
||||
Name: "image",
|
||||
Image: "test/image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
||||
Name: "image",
|
||||
Image: "test/image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: v1.TerminationMessageReadFile,
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
||||
}},
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
SchedulerName: api.DefaultSchedulerName,
|
||||
|
@ -107,11 +108,13 @@ func TestDecodePodList(t *testing.T) {
|
|||
DNSPolicy: v1.DNSClusterFirst,
|
||||
TerminationGracePeriodSeconds: &grace,
|
||||
Containers: []v1.Container{{
|
||||
Name: "image",
|
||||
Image: "test/image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
||||
Name: "image",
|
||||
Image: "test/image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: v1.TerminationMessageReadFile,
|
||||
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
||||
}},
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
SchedulerName: api.DefaultSchedulerName,
|
||||
|
|
|
@ -69,10 +69,11 @@ func CreateValidPod(name, namespace string) *v1.Pod {
|
|||
DNSPolicy: v1.DNSClusterFirst,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "ctr",
|
||||
Image: "image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
||||
Name: "ctr",
|
||||
Image: "image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
||||
TerminationMessagePolicy: v1.TerminationMessageReadFile,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -204,7 +205,7 @@ func TestNewPodAddedSnapshotAndUpdates(t *testing.T) {
|
|||
|
||||
// container updates are separated as UPDATE
|
||||
pod := *podUpdate.Pods[0]
|
||||
pod.Spec.Containers = []v1.Container{{Name: "bar", Image: "test", ImagePullPolicy: v1.PullIfNotPresent}}
|
||||
pod.Spec.Containers = []v1.Container{{Name: "bar", Image: "test", ImagePullPolicy: v1.PullIfNotPresent, TerminationMessagePolicy: v1.TerminationMessageReadFile}}
|
||||
channel <- CreatePodUpdate(kubetypes.ADD, TestSource, &pod)
|
||||
expectPodUpdate(t, ch, CreatePodUpdate(kubetypes.UPDATE, TestSource, &pod))
|
||||
}
|
||||
|
@ -222,7 +223,7 @@ func TestNewPodAddedSnapshot(t *testing.T) {
|
|||
|
||||
// container updates are separated as UPDATE
|
||||
pod := *podUpdate.Pods[0]
|
||||
pod.Spec.Containers = []v1.Container{{Name: "bar", Image: "test", ImagePullPolicy: v1.PullIfNotPresent}}
|
||||
pod.Spec.Containers = []v1.Container{{Name: "bar", Image: "test", ImagePullPolicy: v1.PullIfNotPresent, TerminationMessagePolicy: v1.TerminationMessageReadFile}}
|
||||
channel <- CreatePodUpdate(kubetypes.ADD, TestSource, &pod)
|
||||
expectPodUpdate(t, ch, CreatePodUpdate(kubetypes.SET, TestSource, &pod))
|
||||
}
|
||||
|
@ -240,7 +241,7 @@ func TestNewPodAddedUpdatedRemoved(t *testing.T) {
|
|||
|
||||
// an kubetypes.ADD should be converted to kubetypes.UPDATE
|
||||
pod := CreateValidPod("foo", "new")
|
||||
pod.Spec.Containers = []v1.Container{{Name: "bar", Image: "test", ImagePullPolicy: v1.PullIfNotPresent}}
|
||||
pod.Spec.Containers = []v1.Container{{Name: "bar", Image: "test", ImagePullPolicy: v1.PullIfNotPresent, TerminationMessagePolicy: v1.TerminationMessageReadFile}}
|
||||
podUpdate = CreatePodUpdate(kubetypes.ADD, TestSource, pod)
|
||||
channel <- podUpdate
|
||||
expectPodUpdate(t, ch, CreatePodUpdate(kubetypes.UPDATE, TestSource, pod))
|
||||
|
@ -282,7 +283,7 @@ func TestNewPodAddedUpdatedSet(t *testing.T) {
|
|||
|
||||
// should be converted to an kubetypes.ADD, kubetypes.REMOVE, and kubetypes.UPDATE
|
||||
pod := CreateValidPod("foo2", "new")
|
||||
pod.Spec.Containers = []v1.Container{{Name: "bar", Image: "test", ImagePullPolicy: v1.PullIfNotPresent}}
|
||||
pod.Spec.Containers = []v1.Container{{Name: "bar", Image: "test", ImagePullPolicy: v1.PullIfNotPresent, TerminationMessagePolicy: v1.TerminationMessageReadFile}}
|
||||
podUpdate = CreatePodUpdate(kubetypes.SET, TestSource, pod, CreateValidPod("foo3", "new"), CreateValidPod("foo4", "new"))
|
||||
channel <- podUpdate
|
||||
expectPodUpdate(t, ch,
|
||||
|
|
|
@ -210,9 +210,11 @@ func getTestCases(hostname types.NodeName) []*testCase {
|
|||
Containers: []v1.Container{{
|
||||
Name: "image",
|
||||
Image: "test/image",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "Always",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "Always",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
||||
TerminationMessagePolicy: v1.TerminationMessageReadFile,
|
||||
}},
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
SchedulerName: api.DefaultSchedulerName,
|
||||
},
|
||||
|
|
|
@ -145,7 +145,7 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||
},
|
||||
Spec: v1.PodSpec{
|
||||
NodeName: string(nodeName),
|
||||
Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}},
|
||||
Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways, TerminationMessagePolicy: v1.TerminationMessageReadFile}},
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
SchedulerName: api.DefaultSchedulerName,
|
||||
},
|
||||
|
@ -174,8 +174,9 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||
Containers: []v1.Container{{
|
||||
Name: "1",
|
||||
Image: "foo",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "Always",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "Always",
|
||||
TerminationMessagePolicy: v1.TerminationMessageReadFile,
|
||||
}},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
|
@ -198,7 +199,7 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||
},
|
||||
Spec: v1.PodSpec{
|
||||
NodeName: nodeName,
|
||||
Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}},
|
||||
Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways, TerminationMessagePolicy: v1.TerminationMessageReadFile}},
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
SchedulerName: api.DefaultSchedulerName,
|
||||
},
|
||||
|
@ -213,7 +214,7 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||
},
|
||||
Spec: v1.PodSpec{
|
||||
NodeName: nodeName,
|
||||
Containers: []v1.Container{{Name: "2", Image: "bar:bartag", ImagePullPolicy: ""}},
|
||||
Containers: []v1.Container{{Name: "2", Image: "bar:bartag", ImagePullPolicy: "", TerminationMessagePolicy: v1.TerminationMessageReadFile}},
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
SchedulerName: api.DefaultSchedulerName,
|
||||
},
|
||||
|
@ -244,8 +245,9 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||
Containers: []v1.Container{{
|
||||
Name: "1",
|
||||
Image: "foo",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "Always",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "Always",
|
||||
TerminationMessagePolicy: v1.TerminationMessageReadFile,
|
||||
}},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
|
@ -271,8 +273,9 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||
Containers: []v1.Container{{
|
||||
Name: "2",
|
||||
Image: "bar:bartag",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: v1.TerminationMessageReadFile,
|
||||
}},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
|
|
|
@ -32,6 +32,7 @@ type OSInterface interface {
|
|||
Remove(path string) error
|
||||
RemoveAll(path string) error
|
||||
Create(path string) (*os.File, error)
|
||||
Chmod(path string, perm os.FileMode) error
|
||||
Hostname() (name string, err error)
|
||||
Chtimes(path string, atime time.Time, mtime time.Time) error
|
||||
Pipe() (r *os.File, w *os.File, err error)
|
||||
|
@ -73,6 +74,12 @@ func (RealOS) Create(path string) (*os.File, error) {
|
|||
return os.Create(path)
|
||||
}
|
||||
|
||||
// Chmod will change the permissions on the specified path or return
|
||||
// an error.
|
||||
func (RealOS) Chmod(path string, perm os.FileMode) error {
|
||||
return os.Chmod(path, perm)
|
||||
}
|
||||
|
||||
// Hostname will call os.Hostname to return the hostname.
|
||||
func (RealOS) Hostname() (name string, err error) {
|
||||
return os.Hostname()
|
||||
|
|
|
@ -626,3 +626,19 @@ func (s SortContainerStatusesByCreationTime) Swap(i, j int) { s[i], s[j] = s[j],
|
|||
func (s SortContainerStatusesByCreationTime) Less(i, j int) bool {
|
||||
return s[i].CreatedAt.Before(s[j].CreatedAt)
|
||||
}
|
||||
|
||||
const (
|
||||
// MaxPodTerminationMessageLogLength is the maximum bytes any one pod may have written
|
||||
// as termination message output across all containers. Containers will be evenly truncated
|
||||
// until output is below this limit.
|
||||
MaxPodTerminationMessageLogLength = 1024 * 12
|
||||
// MaxContainerTerminationMessageLength is the upper bound any one container may write to
|
||||
// its termination message path. Contents above this length will be truncated.
|
||||
MaxContainerTerminationMessageLength = 1024 * 4
|
||||
// MaxContainerTerminationMessageLogLength is the maximum bytes any one container will
|
||||
// have written to its termination message when the message is read from the logs.
|
||||
MaxContainerTerminationMessageLogLength = 1024 * 2
|
||||
// MaxContainerTerminationMessageLogLines is the maximum number of previous lines of
|
||||
// log output that the termination message can contain.
|
||||
MaxContainerTerminationMessageLogLines = 80
|
||||
)
|
||||
|
|
|
@ -83,6 +83,11 @@ func (FakeOS) Create(path string) (*os.File, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// Chmod is a fake call that returns nil.
|
||||
func (FakeOS) Chmod(path string, perm os.FileMode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hostname is a fake call that returns nil.
|
||||
func (f *FakeOS) Hostname() (name string, err error) {
|
||||
return f.HostName, nil
|
||||
|
|
|
@ -52,8 +52,10 @@ go_library(
|
|||
"//pkg/util/procfs:go_default_library",
|
||||
"//pkg/util/selinux:go_default_library",
|
||||
"//pkg/util/strings:go_default_library",
|
||||
"//pkg/util/tail:go_default_library",
|
||||
"//pkg/util/term:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor:github.com/armon/circbuf",
|
||||
"//vendor:github.com/docker/distribution/digest",
|
||||
"//vendor:github.com/docker/distribution/reference",
|
||||
"//vendor:github.com/docker/docker/pkg/jsonmessage",
|
||||
|
|
|
@ -33,6 +33,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/circbuf"
|
||||
dockertypes "github.com/docker/engine-api/types"
|
||||
dockercontainer "github.com/docker/engine-api/types/container"
|
||||
dockerstrslice "github.com/docker/engine-api/types/strslice"
|
||||
|
@ -70,6 +71,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/util/procfs"
|
||||
"k8s.io/kubernetes/pkg/util/selinux"
|
||||
utilstrings "k8s.io/kubernetes/pkg/util/strings"
|
||||
"k8s.io/kubernetes/pkg/util/tail"
|
||||
"k8s.io/kubernetes/pkg/util/term"
|
||||
utilversion "k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
@ -482,19 +484,12 @@ func (dm *DockerManager) inspectContainer(id string, podName, podNamespace strin
|
|||
startedAt = createdAt
|
||||
}
|
||||
|
||||
terminationMessagePath := containerInfo.TerminationMessagePath
|
||||
if terminationMessagePath != "" {
|
||||
for _, mount := range iResult.Mounts {
|
||||
if mount.Destination == terminationMessagePath {
|
||||
path := mount.Source
|
||||
if data, err := ioutil.ReadFile(path); err != nil {
|
||||
message = fmt.Sprintf("Error on reading termination-log %s: %v", path, err)
|
||||
} else {
|
||||
message = string(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
// retrieve the termination message from logs, file, or file with fallback to logs in case of failure
|
||||
fallbackToLogs := containerInfo.TerminationMessagePolicy == v1.TerminationMessageFallbackToLogsOnError && (iResult.State.ExitCode != 0 || iResult.State.OOMKilled)
|
||||
if msg := getTerminationMessage(dm.c, iResult, containerInfo.TerminationMessagePath, fallbackToLogs); len(msg) > 0 {
|
||||
message = msg
|
||||
}
|
||||
|
||||
status.State = kubecontainer.ContainerStateExited
|
||||
status.Message = message
|
||||
status.Reason = reason
|
||||
|
@ -508,6 +503,49 @@ func (dm *DockerManager) inspectContainer(id string, podName, podNamespace strin
|
|||
return &status, "", nil
|
||||
}
|
||||
|
||||
func getTerminationMessage(c DockerInterface, iResult *dockertypes.ContainerJSON, terminationMessagePath string, fallbackToLogs bool) string {
|
||||
if len(terminationMessagePath) != 0 {
|
||||
for _, mount := range iResult.Mounts {
|
||||
if mount.Destination != terminationMessagePath {
|
||||
continue
|
||||
}
|
||||
path := mount.Source
|
||||
data, _, err := tail.ReadAtMost(path, kubecontainer.MaxContainerTerminationMessageLength)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error on reading termination log %s: %v", path, err)
|
||||
}
|
||||
if !fallbackToLogs || len(data) != 0 {
|
||||
return string(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !fallbackToLogs {
|
||||
return ""
|
||||
}
|
||||
|
||||
return readLastStringFromContainerLogs(c, iResult.Name)
|
||||
}
|
||||
|
||||
// readLastStringFromContainerLogs attempts to a certain amount from the end of the logs for containerName.
|
||||
// It will attempt to avoid reading excessive logs from the server, which may result in underestimating the amount
|
||||
// of logs to fetch (such that the length of the response message is < max).
|
||||
func readLastStringFromContainerLogs(c DockerInterface, containerName string) string {
|
||||
logOptions := dockertypes.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
ShowStderr: true,
|
||||
}
|
||||
buf, _ := circbuf.NewBuffer(kubecontainer.MaxContainerTerminationMessageLogLength)
|
||||
streamOptions := StreamOptions{
|
||||
ErrorStream: buf,
|
||||
OutputStream: buf,
|
||||
}
|
||||
logOptions.Tail = strconv.FormatInt(kubecontainer.MaxContainerTerminationMessageLogLines, 10)
|
||||
if err := c.Logs(containerName, logOptions, streamOptions); err != nil {
|
||||
return fmt.Sprintf("Error on reading termination message from logs: %v", err)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// makeEnvList converts EnvVar list to a list of strings, in the form of
|
||||
// '<key>=<value>', which can be understood by docker.
|
||||
func makeEnvList(envs []kubecontainer.EnvVar) (result []string) {
|
||||
|
@ -672,17 +710,24 @@ func (dm *DockerManager) runContainer(
|
|||
fs, err := os.Create(containerLogPath)
|
||||
if err != nil {
|
||||
// TODO: Clean up the previously created dir? return the error?
|
||||
glog.Errorf("Error on creating termination-log file %q: %v", containerLogPath, err)
|
||||
utilruntime.HandleError(fmt.Errorf("error creating termination-log file %q: %v", containerLogPath, err))
|
||||
} else {
|
||||
fs.Close() // Close immediately; we're just doing a `touch` here
|
||||
b := fmt.Sprintf("%s:%s", containerLogPath, container.TerminationMessagePath)
|
||||
|
||||
// Chmod is needed because ioutil.WriteFile() ends up calling
|
||||
// open(2) to create the file, so the final mode used is "mode &
|
||||
// ~umask". But we want to make sure the specified mode is used
|
||||
// in the file no matter what the umask is.
|
||||
if err := os.Chmod(containerLogPath, 0666); err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("unable to set termination-log file permissions %q: %v", containerLogPath, err))
|
||||
}
|
||||
|
||||
// Have docker relabel the termination log path if SELinux is
|
||||
// enabled.
|
||||
b := fmt.Sprintf("%s:%s", containerLogPath, container.TerminationMessagePath)
|
||||
if selinux.SELinuxEnabled() {
|
||||
b += ":Z"
|
||||
}
|
||||
|
||||
binds = append(binds, b)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,11 +39,12 @@ const (
|
|||
kubernetesPodDeletionGracePeriodLabel = "io.kubernetes.pod.deletionGracePeriod"
|
||||
kubernetesPodTerminationGracePeriodLabel = "io.kubernetes.pod.terminationGracePeriod"
|
||||
|
||||
kubernetesContainerHashLabel = "io.kubernetes.container.hash"
|
||||
kubernetesContainerRestartCountLabel = "io.kubernetes.container.restartCount"
|
||||
kubernetesContainerTerminationMessagePathLabel = "io.kubernetes.container.terminationMessagePath"
|
||||
kubernetesContainerPreStopHandlerLabel = "io.kubernetes.container.preStopHandler"
|
||||
kubernetesContainerPortsLabel = "io.kubernetes.container.ports" // Added in 1.4
|
||||
kubernetesContainerHashLabel = "io.kubernetes.container.hash"
|
||||
kubernetesContainerRestartCountLabel = "io.kubernetes.container.restartCount"
|
||||
kubernetesContainerTerminationMessagePathLabel = "io.kubernetes.container.terminationMessagePath"
|
||||
kubernetesContainerTerminationMessagePolicyLabel = "io.kubernetes.container.terminationMessagePolicy"
|
||||
kubernetesContainerPreStopHandlerLabel = "io.kubernetes.container.preStopHandler"
|
||||
kubernetesContainerPortsLabel = "io.kubernetes.container.ports" // Added in 1.4
|
||||
|
||||
// TODO(random-liu): Keep this for old containers, remove this when we drop support for v1.1.
|
||||
kubernetesPodLabel = "io.kubernetes.pod.data"
|
||||
|
@ -63,6 +64,7 @@ type labelledContainerInfo struct {
|
|||
Hash string
|
||||
RestartCount int
|
||||
TerminationMessagePath string
|
||||
TerminationMessagePolicy v1.TerminationMessagePolicy
|
||||
PreStopHandler *v1.Handler
|
||||
Ports []v1.ContainerPort
|
||||
}
|
||||
|
@ -83,6 +85,7 @@ func newLabels(container *v1.Container, pod *v1.Pod, restartCount int, enableCus
|
|||
labels[kubernetesContainerHashLabel] = strconv.FormatUint(kubecontainer.HashContainer(container), 16)
|
||||
labels[kubernetesContainerRestartCountLabel] = strconv.Itoa(restartCount)
|
||||
labels[kubernetesContainerTerminationMessagePathLabel] = container.TerminationMessagePath
|
||||
labels[kubernetesContainerTerminationMessagePolicyLabel] = string(container.TerminationMessagePolicy)
|
||||
if container.Lifecycle != nil && container.Lifecycle.PreStop != nil {
|
||||
// Using json enconding so that the PreStop handler object is readable after writing as a label
|
||||
rawPreStop, err := json.Marshal(container.Lifecycle.PreStop)
|
||||
|
@ -118,7 +121,8 @@ func getContainerInfoFromLabel(labels map[string]string) *labelledContainerInfo
|
|||
PodUID: kubetypes.UID(getStringValueFromLabel(labels, types.KubernetesPodUIDLabel)),
|
||||
Name: getStringValueFromLabel(labels, types.KubernetesContainerNameLabel),
|
||||
Hash: getStringValueFromLabel(labels, kubernetesContainerHashLabel),
|
||||
TerminationMessagePath: getStringValueFromLabel(labels, kubernetesContainerTerminationMessagePathLabel),
|
||||
TerminationMessagePath: getStringValueFromLabel(labels, kubernetesContainerTerminationMessagePathLabel),
|
||||
TerminationMessagePolicy: v1.TerminationMessagePolicy(getStringValueFromLabel(labels, kubernetesContainerTerminationMessagePolicyLabel)),
|
||||
}
|
||||
if containerInfo.RestartCount, err = getIntValueFromLabel(labels, kubernetesContainerRestartCountLabel); err != nil {
|
||||
logError(containerInfo, kubernetesContainerRestartCountLabel, err)
|
||||
|
|
|
@ -47,7 +47,9 @@ go_library(
|
|||
"//pkg/securitycontext:go_default_library",
|
||||
"//pkg/util/parsers:go_default_library",
|
||||
"//pkg/util/selinux:go_default_library",
|
||||
"//pkg/util/tail:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor:github.com/armon/circbuf",
|
||||
"//vendor:github.com/docker/docker/pkg/jsonlog",
|
||||
"//vendor:github.com/fsnotify/fsnotify",
|
||||
"//vendor:github.com/golang/glog",
|
||||
|
|
|
@ -19,7 +19,6 @@ package kuberuntime
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"os"
|
||||
|
@ -28,7 +27,9 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/circbuf"
|
||||
"github.com/golang/glog"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kubetypes "k8s.io/apimachinery/pkg/types"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
|
@ -41,6 +42,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util/format"
|
||||
"k8s.io/kubernetes/pkg/util/selinux"
|
||||
"k8s.io/kubernetes/pkg/util/tail"
|
||||
)
|
||||
|
||||
// startContainer starts a container and returns a message indicates why it is failed on error.
|
||||
|
@ -272,9 +274,18 @@ func (m *kubeGenericRuntimeManager) makeMounts(opts *kubecontainer.RunContainerO
|
|||
containerLogPath := filepath.Join(opts.PodContainerDir, cid)
|
||||
fs, err := m.osInterface.Create(containerLogPath)
|
||||
if err != nil {
|
||||
glog.Errorf("Error on creating termination-log file %q: %v", containerLogPath, err)
|
||||
utilruntime.HandleError(fmt.Errorf("error on creating termination-log file %q: %v", containerLogPath, err))
|
||||
} else {
|
||||
fs.Close()
|
||||
|
||||
// Chmod is needed because ioutil.WriteFile() ends up calling
|
||||
// open(2) to create the file, so the final mode used is "mode &
|
||||
// ~umask". But we want to make sure the specified mode is used
|
||||
// in the file no matter what the umask is.
|
||||
if err := m.osInterface.Chmod(containerLogPath, 0666); err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("unable to set termination-log file permissions %q: %v", containerLogPath, err))
|
||||
}
|
||||
|
||||
selinuxRelabel := selinux.SELinuxEnabled()
|
||||
volumeMounts = append(volumeMounts, &runtimeapi.Mount{
|
||||
HostPath: containerLogPath,
|
||||
|
@ -325,29 +336,36 @@ func makeUID() string {
|
|||
return fmt.Sprintf("%08x", rand.Uint32())
|
||||
}
|
||||
|
||||
// getTerminationMessage gets termination message of the container.
|
||||
func getTerminationMessage(status *runtimeapi.ContainerStatus, kubeStatus *kubecontainer.ContainerStatus, terminationMessagePath string) string {
|
||||
message := ""
|
||||
|
||||
if !kubeStatus.FinishedAt.IsZero() || kubeStatus.ExitCode != 0 {
|
||||
if terminationMessagePath == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// getTerminationMessage looks on the filesystem for the provided termination message path, returning a limited
|
||||
// amount of those bytes, or returns true if the logs should be checked.
|
||||
func getTerminationMessage(status *runtimeapi.ContainerStatus, terminationMessagePath string, fallbackToLogs bool) (string, bool) {
|
||||
if len(terminationMessagePath) != 0 {
|
||||
for _, mount := range status.Mounts {
|
||||
if mount.ContainerPath == terminationMessagePath {
|
||||
path := mount.HostPath
|
||||
if data, err := ioutil.ReadFile(path); err != nil {
|
||||
message = fmt.Sprintf("Error on reading termination-log %s: %v", path, err)
|
||||
} else {
|
||||
message = string(data)
|
||||
}
|
||||
break
|
||||
if mount.ContainerPath != terminationMessagePath {
|
||||
continue
|
||||
}
|
||||
path := mount.HostPath
|
||||
data, _, err := tail.ReadAtMost(path, kubecontainer.MaxContainerTerminationMessageLength)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error on reading termination log %s: %v", path, err), false
|
||||
}
|
||||
if !fallbackToLogs || len(data) != 0 {
|
||||
return string(data), false
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fallbackToLogs
|
||||
}
|
||||
|
||||
return message
|
||||
// readLastStringFromContainerLogs attempts to read up to the max log length from the end of the CRI log represented
|
||||
// by path. It reads up to max log lines.
|
||||
func readLastStringFromContainerLogs(path string) string {
|
||||
value := int64(kubecontainer.MaxContainerTerminationMessageLogLines)
|
||||
buf, _ := circbuf.NewBuffer(kubecontainer.MaxContainerTerminationMessageLogLength)
|
||||
if err := ReadLogs(path, &v1.PodLogOptions{TailLines: &value}, buf, buf); err != nil {
|
||||
return fmt.Sprintf("Error on reading termination message from logs: %v", err)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// getPodContainerStatuses gets all containers' statuses for the pod.
|
||||
|
@ -393,13 +411,19 @@ func (m *kubeGenericRuntimeManager) getPodContainerStatuses(uid kubetypes.UID, n
|
|||
cStatus.Message = status.Message
|
||||
cStatus.ExitCode = int(status.ExitCode)
|
||||
cStatus.FinishedAt = time.Unix(0, status.FinishedAt)
|
||||
|
||||
fallbackToLogs := annotatedInfo.TerminationMessagePolicy == v1.TerminationMessageFallbackToLogsOnError && (cStatus.ExitCode != 0 || cStatus.Reason == "OOMKilled")
|
||||
tMessage, checkLogs := getTerminationMessage(status, annotatedInfo.TerminationMessagePath, fallbackToLogs)
|
||||
if checkLogs {
|
||||
path := buildFullContainerLogsPath(uid, labeledInfo.ContainerName, annotatedInfo.RestartCount)
|
||||
tMessage = readLastStringFromContainerLogs(path)
|
||||
}
|
||||
// Use the termination message written by the application is not empty
|
||||
if len(tMessage) != 0 {
|
||||
cStatus.Message = tMessage
|
||||
}
|
||||
}
|
||||
|
||||
tMessage := getTerminationMessage(status, cStatus, annotatedInfo.TerminationMessagePath)
|
||||
// Use the termination message written by the application is not empty
|
||||
if len(tMessage) != 0 {
|
||||
cStatus.Message = tMessage
|
||||
}
|
||||
statuses[i] = cStatus
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/util/tail"
|
||||
)
|
||||
|
||||
// Notice that the current kuberuntime logs implementation doesn't handle
|
||||
|
@ -120,7 +121,7 @@ func ReadLogs(path string, apiOpts *v1.PodLogOptions, stdout, stderr io.Writer)
|
|||
opts := newLogOptions(apiOpts, time.Now())
|
||||
|
||||
// Search start point based on tail line.
|
||||
start, err := tail(f, opts.tail)
|
||||
start, err := tail.FindTailLineStartIndex(f, opts.tail)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to tail %d lines of log file %q: %v", opts.tail, path, err)
|
||||
}
|
||||
|
@ -347,40 +348,3 @@ func (w *logWriter) write(msg *logMessage) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// tail returns the start of last nth line.
|
||||
// * If n < 0, return the beginning of the file.
|
||||
// * If n >= 0, return the beginning of last nth line.
|
||||
// Notice that if the last line is incomplete (no end-of-line), it will not be counted
|
||||
// as one line.
|
||||
func tail(f io.ReadSeeker, n int64) (int64, error) {
|
||||
if n < 0 {
|
||||
return 0, nil
|
||||
}
|
||||
size, err := f.Seek(0, os.SEEK_END)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var left, cnt int64
|
||||
buf := make([]byte, blockSize)
|
||||
for right := size; right > 0 && cnt <= n; right -= blockSize {
|
||||
left = right - blockSize
|
||||
if left < 0 {
|
||||
left = 0
|
||||
buf = make([]byte, right)
|
||||
}
|
||||
if _, err := f.Seek(left, os.SEEK_SET); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := f.Read(buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cnt += int64(bytes.Count(buf, eol))
|
||||
}
|
||||
for ; cnt > n; cnt-- {
|
||||
idx := bytes.Index(buf, eol) + 1
|
||||
buf = buf[idx:]
|
||||
left += int64(idx)
|
||||
}
|
||||
return left, nil
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package kuberuntime
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -242,28 +241,3 @@ func TestWriteLogsWithBytesLimit(t *testing.T) {
|
|||
assert.Equal(t, test.expectStderr, stderrBuf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTail(t *testing.T) {
|
||||
line := strings.Repeat("a", blockSize)
|
||||
testBytes := []byte(line + "\n" +
|
||||
line + "\n" +
|
||||
line + "\n" +
|
||||
line + "\n" +
|
||||
line[blockSize/2:]) // incomplete line
|
||||
|
||||
for c, test := range []struct {
|
||||
n int64
|
||||
start int64
|
||||
}{
|
||||
{n: -1, start: 0},
|
||||
{n: 0, start: int64(len(line)+1) * 4},
|
||||
{n: 1, start: int64(len(line)+1) * 3},
|
||||
{n: 9999, start: 0},
|
||||
} {
|
||||
t.Logf("TestCase #%d: %+v", c, test)
|
||||
r := bytes.NewReader(testBytes)
|
||||
s, err := tail(r, test.n)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, s, test.start)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,11 +33,12 @@ const (
|
|||
podDeletionGracePeriodLabel = "io.kubernetes.pod.deletionGracePeriod"
|
||||
podTerminationGracePeriodLabel = "io.kubernetes.pod.terminationGracePeriod"
|
||||
|
||||
containerHashLabel = "io.kubernetes.container.hash"
|
||||
containerRestartCountLabel = "io.kubernetes.container.restartCount"
|
||||
containerTerminationMessagePathLabel = "io.kubernetes.container.terminationMessagePath"
|
||||
containerPreStopHandlerLabel = "io.kubernetes.container.preStopHandler"
|
||||
containerPortsLabel = "io.kubernetes.container.ports"
|
||||
containerHashLabel = "io.kubernetes.container.hash"
|
||||
containerRestartCountLabel = "io.kubernetes.container.restartCount"
|
||||
containerTerminationMessagePathLabel = "io.kubernetes.container.terminationMessagePath"
|
||||
containerTerminationMessagePolicyLabel = "io.kubernetes.container.terminationMessagePolicy"
|
||||
containerPreStopHandlerLabel = "io.kubernetes.container.preStopHandler"
|
||||
containerPortsLabel = "io.kubernetes.container.ports"
|
||||
|
||||
// kubernetesManagedLabel is used to distinguish whether a container/sandbox is managed by kubelet or not
|
||||
kubernetesManagedLabel = "io.kubernetes.managed"
|
||||
|
@ -69,6 +70,7 @@ type annotatedContainerInfo struct {
|
|||
PodDeletionGracePeriod *int64
|
||||
PodTerminationGracePeriod *int64
|
||||
TerminationMessagePath string
|
||||
TerminationMessagePolicy v1.TerminationMessagePolicy
|
||||
PreStopHandler *v1.Handler
|
||||
ContainerPorts []v1.ContainerPort
|
||||
}
|
||||
|
@ -113,6 +115,7 @@ func newContainerAnnotations(container *v1.Container, pod *v1.Pod, restartCount
|
|||
annotations[containerHashLabel] = strconv.FormatUint(kubecontainer.HashContainer(container), 16)
|
||||
annotations[containerRestartCountLabel] = strconv.Itoa(restartCount)
|
||||
annotations[containerTerminationMessagePathLabel] = container.TerminationMessagePath
|
||||
annotations[containerTerminationMessagePolicyLabel] = string(container.TerminationMessagePolicy)
|
||||
|
||||
if pod.DeletionGracePeriodSeconds != nil {
|
||||
annotations[podDeletionGracePeriodLabel] = strconv.FormatInt(*pod.DeletionGracePeriodSeconds, 10)
|
||||
|
@ -192,7 +195,8 @@ func isManagedByKubelet(labels map[string]string) bool {
|
|||
func getContainerInfoFromAnnotations(annotations map[string]string) *annotatedContainerInfo {
|
||||
var err error
|
||||
containerInfo := &annotatedContainerInfo{
|
||||
TerminationMessagePath: getStringValueFromLabel(annotations, containerTerminationMessagePathLabel),
|
||||
TerminationMessagePath: getStringValueFromLabel(annotations, containerTerminationMessagePathLabel),
|
||||
TerminationMessagePolicy: v1.TerminationMessagePolicy(getStringValueFromLabel(annotations, containerTerminationMessagePolicyLabel)),
|
||||
}
|
||||
|
||||
if containerInfo.Hash, err = getUint64ValueFromLabel(annotations, containerHashLabel); err != nil {
|
||||
|
|
|
@ -513,6 +513,10 @@ func (m *manager) needsReconcile(uid types.UID, status v1.PodStatus) bool {
|
|||
// kubelet temporarily.
|
||||
// TODO(random-liu): Remove timestamp related logic after apiserver supports nanosecond or makes it consistent.
|
||||
func normalizeStatus(pod *v1.Pod, status *v1.PodStatus) *v1.PodStatus {
|
||||
bytesPerStatus := kubecontainer.MaxPodTerminationMessageLogLength
|
||||
if containers := len(pod.Spec.Containers) + len(pod.Spec.InitContainers); containers > 0 {
|
||||
bytesPerStatus = bytesPerStatus / containers
|
||||
}
|
||||
normalizeTimeStamp := func(t *metav1.Time) {
|
||||
*t = t.Rfc3339Copy()
|
||||
}
|
||||
|
@ -523,6 +527,9 @@ func normalizeStatus(pod *v1.Pod, status *v1.PodStatus) *v1.PodStatus {
|
|||
if c.Terminated != nil {
|
||||
normalizeTimeStamp(&c.Terminated.StartedAt)
|
||||
normalizeTimeStamp(&c.Terminated.FinishedAt)
|
||||
if len(c.Terminated.Message) > bytesPerStatus {
|
||||
c.Terminated.Message = c.Terminated.Message[:bytesPerStatus]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,21 +20,21 @@ import (
|
|||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
kubepod "k8s.io/kubernetes/pkg/kubelet/pod"
|
||||
podtest "k8s.io/kubernetes/pkg/kubelet/pod/testing"
|
||||
|
@ -480,6 +480,40 @@ func TestStatusEquality(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestStatusNormalizationEnforcesMaxBytes(t *testing.T) {
|
||||
pod := v1.Pod{
|
||||
Spec: v1.PodSpec{},
|
||||
}
|
||||
containerStatus := []v1.ContainerStatus{}
|
||||
for i := 0; i < 48; i++ {
|
||||
s := v1.ContainerStatus{
|
||||
Name: fmt.Sprintf("container%d", i),
|
||||
LastTerminationState: v1.ContainerState{
|
||||
Terminated: &v1.ContainerStateTerminated{
|
||||
Message: strings.Repeat("abcdefgh", int(24+i%3)),
|
||||
},
|
||||
},
|
||||
}
|
||||
containerStatus = append(containerStatus, s)
|
||||
}
|
||||
podStatus := v1.PodStatus{
|
||||
InitContainerStatuses: containerStatus[:24],
|
||||
ContainerStatuses: containerStatus[24:],
|
||||
}
|
||||
result := normalizeStatus(&pod, &podStatus)
|
||||
count := 0
|
||||
for _, s := range result.InitContainerStatuses {
|
||||
l := len(s.LastTerminationState.Terminated.Message)
|
||||
if l < 192 || l > 256 {
|
||||
t.Errorf("container message had length %d", l)
|
||||
}
|
||||
count += l
|
||||
}
|
||||
if count > kubecontainer.MaxPodTerminationMessageLogLength {
|
||||
t.Errorf("message length not truncated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaticPod(t *testing.T) {
|
||||
staticPod := getTestPod()
|
||||
staticPod.Annotations = map[string]string{kubetypes.ConfigSourceAnnotationKey: "file"}
|
||||
|
|
|
@ -45,7 +45,7 @@ func TestCronJobStrategy(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
}
|
||||
scheduledJob := &batch.CronJob{
|
||||
|
@ -106,7 +106,7 @@ func TestCronJobStatusStrategy(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
}
|
||||
oldSchedule := "* * * * ?"
|
||||
|
|
|
@ -64,9 +64,10 @@ func validNewJob() *batch.Job {
|
|||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
|
|
|
@ -54,7 +54,7 @@ func TestJobStrategy(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
}
|
||||
job := &batch.Job{
|
||||
|
@ -111,7 +111,7 @@ func TestJobStrategyWithGeneration(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
}
|
||||
job := &batch.Job{
|
||||
|
@ -170,7 +170,7 @@ func TestJobStatusStrategy(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
}
|
||||
oldParallelism := int32(10)
|
||||
|
|
|
@ -77,9 +77,10 @@ func validNewController() *api.ReplicationController {
|
|||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
|
|
|
@ -44,7 +44,7 @@ func TestControllerStrategy(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ func TestControllerStatusStrategy(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ func TestValidateUpdate(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -68,8 +68,9 @@ func validNewPod() *api.Pod {
|
|||
Image: "test",
|
||||
ImagePullPolicy: api.PullAlways,
|
||||
|
||||
TerminationMessagePath: api.TerminationMessagePathDefault,
|
||||
SecurityContext: securitycontext.ValidInternalSecurityContextWithContainerDefaults(),
|
||||
TerminationMessagePath: api.TerminationMessagePathDefault,
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
SecurityContext: securitycontext.ValidInternalSecurityContextWithContainerDefaults(),
|
||||
},
|
||||
},
|
||||
SecurityContext: &api.PodSecurityContext{},
|
||||
|
@ -678,11 +679,12 @@ func TestEtcdUpdateScheduled(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
NodeName: "machine",
|
||||
Containers: []api.Container{{
|
||||
Name: "foobar",
|
||||
Image: "foo:v2",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
TerminationMessagePath: api.TerminationMessagePathDefault,
|
||||
SecurityContext: securitycontext.ValidInternalSecurityContextWithContainerDefaults(),
|
||||
Name: "foobar",
|
||||
Image: "foo:v2",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
TerminationMessagePath: api.TerminationMessagePathDefault,
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
SecurityContext: securitycontext.ValidInternalSecurityContextWithContainerDefaults(),
|
||||
}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
|
@ -772,6 +774,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
|
|||
expected.Spec.DNSPolicy = api.DNSClusterFirst
|
||||
expected.Spec.Containers[0].ImagePullPolicy = api.PullIfNotPresent
|
||||
expected.Spec.Containers[0].TerminationMessagePath = api.TerminationMessagePathDefault
|
||||
expected.Spec.Containers[0].TerminationMessagePolicy = api.TerminationMessageReadFile
|
||||
expected.Labels = podIn.Labels
|
||||
expected.Status = podIn.Status
|
||||
|
||||
|
|
|
@ -59,7 +59,8 @@ func validNewPodTemplate(name string) *api.PodTemplate {
|
|||
Image: "test",
|
||||
ImagePullPolicy: api.PullAlways,
|
||||
|
||||
TerminationMessagePath: api.TerminationMessagePathDefault,
|
||||
TerminationMessagePath: api.TerminationMessagePathDefault,
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -57,9 +57,10 @@ func newValidDaemonSet() *extensions.DaemonSet {
|
|||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
|
|
|
@ -71,9 +71,10 @@ func validNewDeployment() *extensions.Deployment {
|
|||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
|
|
|
@ -69,9 +69,10 @@ func validNewReplicaSet() *extensions.ReplicaSet {
|
|||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
TerminationMessagePolicy: api.TerminationMessageReadFile,
|
||||
},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
|
|
|
@ -43,7 +43,7 @@ func TestReplicaSetStrategy(t *testing.T) {
|
|||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ filegroup(
|
|||
"//pkg/util/strings:all-srcs",
|
||||
"//pkg/util/sysctl:all-srcs",
|
||||
"//pkg/util/system:all-srcs",
|
||||
"//pkg/util/tail:all-srcs",
|
||||
"//pkg/util/taints:all-srcs",
|
||||
"//pkg/util/term:all-srcs",
|
||||
"//pkg/util/threading:all-srcs",
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["tail_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["tail.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
// blockSize is the block size used in tail.
|
||||
blockSize = 1024
|
||||
)
|
||||
|
||||
var (
|
||||
// eol is the end-of-line sign in the log.
|
||||
eol = []byte{'\n'}
|
||||
)
|
||||
|
||||
// ReadAtMost reads at most max bytes from the end of the file identified by path or
|
||||
// returns an error. It returns true if the file was longer than max. It will
|
||||
// allocate up to max bytes.
|
||||
func ReadAtMost(path string, max int64) ([]byte, bool, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
defer f.Close()
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
size := fi.Size()
|
||||
if size == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
if size < max {
|
||||
max = size
|
||||
}
|
||||
offset, err := f.Seek(-max, os.SEEK_END)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
data, err := ioutil.ReadAll(f)
|
||||
return data, offset > 0, err
|
||||
}
|
||||
|
||||
// FindTailLineStartIndex returns the start of last nth line.
|
||||
// * If n < 0, return the beginning of the file.
|
||||
// * If n >= 0, return the beginning of last nth line.
|
||||
// Notice that if the last line is incomplete (no end-of-line), it will not be counted
|
||||
// as one line.
|
||||
func FindTailLineStartIndex(f io.ReadSeeker, n int64) (int64, error) {
|
||||
if n < 0 {
|
||||
return 0, nil
|
||||
}
|
||||
size, err := f.Seek(0, os.SEEK_END)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var left, cnt int64
|
||||
buf := make([]byte, blockSize)
|
||||
for right := size; right > 0 && cnt <= n; right -= blockSize {
|
||||
left = right - blockSize
|
||||
if left < 0 {
|
||||
left = 0
|
||||
buf = make([]byte, right)
|
||||
}
|
||||
if _, err := f.Seek(left, os.SEEK_SET); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := f.Read(buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cnt += int64(bytes.Count(buf, eol))
|
||||
}
|
||||
for ; cnt > n; cnt-- {
|
||||
idx := bytes.Index(buf, eol) + 1
|
||||
buf = buf[idx:]
|
||||
left += int64(idx)
|
||||
}
|
||||
return left, nil
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTail(t *testing.T) {
|
||||
line := strings.Repeat("a", blockSize)
|
||||
testBytes := []byte(line + "\n" +
|
||||
line + "\n" +
|
||||
line + "\n" +
|
||||
line + "\n" +
|
||||
line[blockSize/2:]) // incomplete line
|
||||
|
||||
for c, test := range []struct {
|
||||
n int64
|
||||
start int64
|
||||
}{
|
||||
{n: -1, start: 0},
|
||||
{n: 0, start: int64(len(line)+1) * 4},
|
||||
{n: 1, start: int64(len(line)+1) * 3},
|
||||
{n: 9999, start: 0},
|
||||
} {
|
||||
t.Logf("TestCase #%d: %+v", c, test)
|
||||
r := bytes.NewReader(testBytes)
|
||||
s, err := FindTailLineStartIndex(r, test.n)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if s != test.start {
|
||||
t.Errorf("%d != %d", s, test.start)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import (
|
|||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
gomegatypes "github.com/onsi/gomega/types"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -128,46 +129,112 @@ while true; do sleep 1; done
|
|||
}
|
||||
})
|
||||
|
||||
It("should report termination message if TerminationMessagePath is set [Conformance]", func() {
|
||||
name := "termination-message-container"
|
||||
terminationMessage := "DONE"
|
||||
terminationMessagePath := "/dev/termination-log"
|
||||
priv := true
|
||||
c := ConformanceContainer{
|
||||
PodClient: f.PodClient(),
|
||||
Container: v1.Container{
|
||||
rootUser := int64(0)
|
||||
nonRootUser := int64(10000)
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
container v1.Container
|
||||
phase v1.PodPhase
|
||||
message gomegatypes.GomegaMatcher
|
||||
}{
|
||||
{
|
||||
name: "if TerminationMessagePath is set [Conformance]",
|
||||
container: v1.Container{
|
||||
Image: "gcr.io/google_containers/busybox:1.24",
|
||||
Name: name,
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{fmt.Sprintf("/bin/echo -n %s > %s", terminationMessage, terminationMessagePath)},
|
||||
TerminationMessagePath: terminationMessagePath,
|
||||
Args: []string{"/bin/echo -n DONE > /dev/termination-log"},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
Privileged: &priv,
|
||||
RunAsUser: &rootUser,
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
}
|
||||
phase: v1.PodSucceeded,
|
||||
message: Equal("DONE"),
|
||||
},
|
||||
|
||||
By("create the container")
|
||||
c.Create()
|
||||
defer c.Delete()
|
||||
{
|
||||
name: "if TerminationMessagePath is set as non-root user and at a non-default path [Conformance]",
|
||||
container: v1.Container{
|
||||
Image: "gcr.io/google_containers/busybox:1.24",
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"/bin/echo -n DONE > /dev/termination-custom-log"},
|
||||
TerminationMessagePath: "/dev/termination-custom-log",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
RunAsUser: &nonRootUser,
|
||||
},
|
||||
},
|
||||
phase: v1.PodSucceeded,
|
||||
message: Equal("DONE"),
|
||||
},
|
||||
|
||||
By("wait for the container to succeed")
|
||||
Eventually(c.GetPhase, retryTimeout, pollInterval).Should(Equal(v1.PodSucceeded))
|
||||
{
|
||||
name: "from log output if TerminationMessagePolicy FallbackToLogOnError is set [Conformance]",
|
||||
container: v1.Container{
|
||||
Image: "gcr.io/google_containers/busybox:1.24",
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"/bin/echo -n DONE; /bin/false"},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
|
||||
},
|
||||
phase: v1.PodFailed,
|
||||
message: Equal("DONE\n"),
|
||||
},
|
||||
|
||||
By("get the container status")
|
||||
status, err := c.GetStatus()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
{
|
||||
name: "as empty when pod succeeds and TerminationMessagePolicy FallbackToLogOnError is set",
|
||||
container: v1.Container{
|
||||
Image: "gcr.io/google_containers/busybox:1.24",
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"/bin/echo DONE; /bin/true"},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
|
||||
},
|
||||
phase: v1.PodSucceeded,
|
||||
message: Equal(""),
|
||||
},
|
||||
|
||||
By("the container should be terminated")
|
||||
Expect(GetContainerState(status.State)).To(Equal(ContainerStateTerminated))
|
||||
{
|
||||
name: "from file when pod succeeds and TerminationMessagePolicy FallbackToLogOnError is set [Conformance]",
|
||||
container: v1.Container{
|
||||
Image: "gcr.io/google_containers/busybox:1.24",
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"/bin/echo -n OK > /dev/termination-log; /bin/echo DONE; /bin/true"},
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError,
|
||||
},
|
||||
phase: v1.PodSucceeded,
|
||||
message: Equal("OK"),
|
||||
},
|
||||
} {
|
||||
It(fmt.Sprintf("should report termination message %s", testCase.name), func() {
|
||||
testCase.container.Name = "termination-message-container"
|
||||
c := ConformanceContainer{
|
||||
PodClient: f.PodClient(),
|
||||
Container: testCase.container,
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
}
|
||||
|
||||
By("the termination message should be set")
|
||||
Expect(status.State.Terminated.Message).Should(Equal(terminationMessage))
|
||||
By("create the container")
|
||||
c.Create()
|
||||
defer c.Delete()
|
||||
|
||||
By("delete the container")
|
||||
Expect(c.Delete()).To(Succeed())
|
||||
})
|
||||
By(fmt.Sprintf("wait for the container to reach %s", testCase.phase))
|
||||
Eventually(c.GetPhase, retryTimeout, pollInterval).Should(Equal(testCase.phase))
|
||||
|
||||
By("get the container status")
|
||||
status, err := c.GetStatus()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("the container should be terminated")
|
||||
Expect(GetContainerState(status.State)).To(Equal(ContainerStateTerminated))
|
||||
|
||||
By("the termination message should be set")
|
||||
Expect(status.State.Terminated.Message).Should(testCase.message)
|
||||
|
||||
By("delete the container")
|
||||
Expect(c.Delete()).To(Succeed())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Context("when running a container with a new image", func() {
|
||||
|
|
|
@ -13718,3 +13718,9 @@ go_library(
|
|||
srcs = ["k8s.io/client-go/third_party/forked/golang/netutil/addr.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "github.com/armon/circbuf",
|
||||
srcs = ["github.com/armon/circbuf/circbuf.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Armon Dadgar
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,28 @@
|
|||
circbuf
|
||||
=======
|
||||
|
||||
This repository provides the `circbuf` package. This provides a `Buffer` object
|
||||
which is a circular (or ring) buffer. It has a fixed size, but can be written
|
||||
to infinitely. Only the last `size` bytes are ever retained. The buffer implements
|
||||
the `io.Writer` interface.
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
Full documentation can be found on [Godoc](http://godoc.org/github.com/armon/circbuf)
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
The `circbuf` package is very easy to use:
|
||||
|
||||
```go
|
||||
buf, _ := NewBuffer(6)
|
||||
buf.Write([]byte("hello world"))
|
||||
|
||||
if string(buf.Bytes()) != " world" {
|
||||
panic("should only have last 6 bytes!")
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package circbuf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Buffer implements a circular buffer. It is a fixed size,
|
||||
// and new writes overwrite older data, such that for a buffer
|
||||
// of size N, for any amount of writes, only the last N bytes
|
||||
// are retained.
|
||||
type Buffer struct {
|
||||
data []byte
|
||||
size int64
|
||||
writeCursor int64
|
||||
written int64
|
||||
}
|
||||
|
||||
// NewBuffer creates a new buffer of a given size. The size
|
||||
// must be greater than 0.
|
||||
func NewBuffer(size int64) (*Buffer, error) {
|
||||
if size <= 0 {
|
||||
return nil, fmt.Errorf("Size must be positive")
|
||||
}
|
||||
|
||||
b := &Buffer{
|
||||
size: size,
|
||||
data: make([]byte, size),
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Write writes up to len(buf) bytes to the internal ring,
|
||||
// overriding older data if necessary.
|
||||
func (b *Buffer) Write(buf []byte) (int, error) {
|
||||
// Account for total bytes written
|
||||
n := len(buf)
|
||||
b.written += int64(n)
|
||||
|
||||
// If the buffer is larger than ours, then we only care
|
||||
// about the last size bytes anyways
|
||||
if int64(n) > b.size {
|
||||
buf = buf[int64(n)-b.size:]
|
||||
}
|
||||
|
||||
// Copy in place
|
||||
remain := b.size - b.writeCursor
|
||||
copy(b.data[b.writeCursor:], buf)
|
||||
if int64(len(buf)) > remain {
|
||||
copy(b.data, buf[remain:])
|
||||
}
|
||||
|
||||
// Update location of the cursor
|
||||
b.writeCursor = ((b.writeCursor + int64(len(buf))) % b.size)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Size returns the size of the buffer
|
||||
func (b *Buffer) Size() int64 {
|
||||
return b.size
|
||||
}
|
||||
|
||||
// TotalWritten provides the total number of bytes written
|
||||
func (b *Buffer) TotalWritten() int64 {
|
||||
return b.written
|
||||
}
|
||||
|
||||
// Bytes provides a slice of the bytes written. This
|
||||
// slice should not be written to.
|
||||
func (b *Buffer) Bytes() []byte {
|
||||
switch {
|
||||
case b.written >= b.size && b.writeCursor == 0:
|
||||
return b.data
|
||||
case b.written > b.size:
|
||||
out := make([]byte, b.size)
|
||||
copy(out, b.data[b.writeCursor:])
|
||||
copy(out[b.size-b.writeCursor:], b.data[:b.writeCursor])
|
||||
return out
|
||||
default:
|
||||
return b.data[:b.writeCursor]
|
||||
}
|
||||
}
|
||||
|
||||
// Reset resets the buffer so it has no content.
|
||||
func (b *Buffer) Reset() {
|
||||
b.writeCursor = 0
|
||||
b.written = 0
|
||||
}
|
||||
|
||||
// String returns the contents of the buffer as a string
|
||||
func (b *Buffer) String() string {
|
||||
return string(b.Bytes())
|
||||
}
|
Loading…
Reference in New Issue