mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
Merge pull request #41116 from lukaszo/ds-updates
Automatic merge from submit-queue (batch tested with PRs 41116, 41804, 42104, 42111, 42120) DaemonSet updates - take 2 It implements https://github.com/kubernetes/community/blob/master/contributors/design-proposals/daemonset-update.md Feature kubernetes/features#124 ```release-note Implement the update feature for DaemonSet. ``` cc @kargakis @janetkuo @mikedanese
This commit is contained in:
commit
73c9fd8cec
@ -41439,6 +41439,11 @@
|
||||
"template"
|
||||
],
|
||||
"properties": {
|
||||
"minReadySeconds": {
|
||||
"description": "MinReadySeconds minimum number of seconds for which a newly created DaemonSet pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"selector": {
|
||||
"description": "Selector is a label query over pods that are managed by the daemon set. Must match in order to be controlled. If empty, defaulted to labels on Pod template. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors",
|
||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector"
|
||||
@ -41446,6 +41451,15 @@
|
||||
"template": {
|
||||
"description": "Template is the object that describes the pod that will be created. The DaemonSet will create exactly one copy of this pod on every node that matches the template's node selector (or on every node if no node selector is specified). More info: http://kubernetes.io/docs/user-guide/replication-controller#pod-template",
|
||||
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.PodTemplateSpec"
|
||||
},
|
||||
"templateGeneration": {
|
||||
"description": "A sequence number representing a specific generation of the template. Populated by the system. It can be set only during the creation.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"updateStrategy": {
|
||||
"description": "UpdateStrategy to replace existing DaemonSet pods with new pods.",
|
||||
"$ref": "#/definitions/io.k8s.kubernetes.pkg.apis.extensions.v1beta1.DaemonSetUpdateStrategy"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -41468,6 +41482,11 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"numberAvailable": {
|
||||
"description": "NumberAvailable is the number of nodes that should be running the daemon pod and have one or more of the daemon pod running and available (ready for at least minReadySeconds)",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"numberMisscheduled": {
|
||||
"description": "NumberMisscheduled is the number of nodes that are running the daemon pod, but are not supposed to run the daemon pod. More info: http://releases.k8s.io/HEAD/docs/admin/daemons.md",
|
||||
"type": "integer",
|
||||
@ -41478,10 +41497,32 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"numberUnavailable": {
|
||||
"description": "NumberUnavailable is the number of nodes that should be running the daemon pod and have none of the daemon pod running and available (ready for at least minReadySeconds)",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"observedGeneration": {
|
||||
"description": "ObservedGeneration is the most recent generation observed by the daemon set controller.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"updatedNumberScheduled": {
|
||||
"description": "UpdatedNumberScheduled is the total number of nodes that are running updated daemon pod",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
},
|
||||
"io.k8s.kubernetes.pkg.apis.extensions.v1beta1.DaemonSetUpdateStrategy": {
|
||||
"properties": {
|
||||
"rollingUpdate": {
|
||||
"description": "Rolling update config params. Present only if DaemonSetUpdateStrategy = RollingUpdate.",
|
||||
"$ref": "#/definitions/io.k8s.kubernetes.pkg.apis.extensions.v1beta1.RollingUpdateDaemonSet"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type of daemon set update. Can be \"RollingUpdate\" or \"OnDelete\". Default is OnDelete.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -42387,6 +42428,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"io.k8s.kubernetes.pkg.apis.extensions.v1beta1.RollingUpdateDaemonSet": {
|
||||
"description": "Spec to control the desired behavior of daemon set rolling update.",
|
||||
"properties": {
|
||||
"maxUnavailable": {
|
||||
"description": "The maximum number of DaemonSet pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of total number of DaemonSet pods at the start of the update (ex: 10%). Absolute number is calculated from percentage by rounding up. This cannot be 0. Default value is 1. Example: when this is set to 30%, 30% of the currently running DaemonSet pods can be stopped for an update at any given time. The update starts by stopping at most 30% of the currently running DaemonSet pods and then brings up new DaemonSet pods in their place. Once the new pods are ready, it then proceeds onto other DaemonSet pods, thus ensuring that at least 70% of original number of DaemonSet pods are available at all times during the update.",
|
||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString"
|
||||
}
|
||||
}
|
||||
},
|
||||
"io.k8s.kubernetes.pkg.apis.extensions.v1beta1.RollingUpdateDeployment": {
|
||||
"description": "Spec to control the desired behavior of rolling update.",
|
||||
"properties": {
|
||||
|
@ -6612,6 +6612,20 @@
|
||||
"template": {
|
||||
"$ref": "v1.PodTemplateSpec",
|
||||
"description": "Template is the object that describes the pod that will be created. The DaemonSet will create exactly one copy of this pod on every node that matches the template's node selector (or on every node if no node selector is specified). More info: http://kubernetes.io/docs/user-guide/replication-controller#pod-template"
|
||||
},
|
||||
"updateStrategy": {
|
||||
"$ref": "v1beta1.DaemonSetUpdateStrategy",
|
||||
"description": "UpdateStrategy to replace existing DaemonSet pods with new pods."
|
||||
},
|
||||
"minReadySeconds": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "MinReadySeconds minimum number of seconds for which a newly created DaemonSet pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready)."
|
||||
},
|
||||
"templateGeneration": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "A sequence number representing a specific generation of the template. Populated by the system. It can be set only during the creation."
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -8439,6 +8453,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta1.DaemonSetUpdateStrategy": {
|
||||
"id": "v1beta1.DaemonSetUpdateStrategy",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of daemon set update. Can be \"RollingUpdate\" or \"OnDelete\". Default is OnDelete."
|
||||
},
|
||||
"rollingUpdate": {
|
||||
"$ref": "v1beta1.RollingUpdateDaemonSet",
|
||||
"description": "Rolling update config params. Present only if DaemonSetUpdateStrategy = RollingUpdate."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta1.RollingUpdateDaemonSet": {
|
||||
"id": "v1beta1.RollingUpdateDaemonSet",
|
||||
"description": "Spec to control the desired behavior of daemon set rolling update.",
|
||||
"properties": {
|
||||
"maxUnavailable": {
|
||||
"type": "string",
|
||||
"description": "The maximum number of DaemonSet pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of total number of DaemonSet pods at the start of the update (ex: 10%). Absolute number is calculated from percentage by rounding up. This cannot be 0. Default value is 1. Example: when this is set to 30%, 30% of the currently running DaemonSet pods can be stopped for an update at any given time. The update starts by stopping at most 30% of the currently running DaemonSet pods and then brings up new DaemonSet pods in their place. Once the new pods are ready, it then proceeds onto other DaemonSet pods, thus ensuring that at least 70% of original number of DaemonSet pods are available at all times during the update."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta1.DaemonSetStatus": {
|
||||
"id": "v1beta1.DaemonSetStatus",
|
||||
"description": "DaemonSetStatus represents the current status of a daemon set.",
|
||||
@ -8473,6 +8510,21 @@
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "ObservedGeneration is the most recent generation observed by the daemon set controller."
|
||||
},
|
||||
"updatedNumberScheduled": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "UpdatedNumberScheduled is the total number of nodes that are running updated daemon pod"
|
||||
},
|
||||
"numberAvailable": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "NumberAvailable is the number of nodes that should be running the daemon pod and have one or more of the daemon pod running and available (ready for at least minReadySeconds)"
|
||||
},
|
||||
"numberUnavailable": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "NumberUnavailable is the number of nodes that should be running the daemon pod and have none of the daemon pod running and available (ready for at least minReadySeconds)"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -661,6 +661,27 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">integer (int64)</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">updatedNumberScheduled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">UpdatedNumberScheduled is the total number of nodes that are running updated daemon pod</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">integer (int32)</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">numberAvailable</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">NumberAvailable is the number of nodes that should be running the daemon pod and have one or more of the daemon pod running and available (ready for at least minReadySeconds)</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">integer (int32)</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">numberUnavailable</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">NumberUnavailable is the number of nodes that should be running the daemon pod and have none of the daemon pod running and available (ready for at least minReadySeconds)</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">integer (int32)</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -1892,6 +1913,40 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1beta1_rollingupdatedaemonset">v1beta1.RollingUpdateDaemonSet</h3>
|
||||
<div class="paragraph">
|
||||
<p>Spec to control the desired behavior of daemon set rolling update.</p>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all" style="width:100%; ">
|
||||
<colgroup>
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tableblock halign-left valign-top">Name</th>
|
||||
<th class="tableblock halign-left valign-top">Description</th>
|
||||
<th class="tableblock halign-left valign-top">Required</th>
|
||||
<th class="tableblock halign-left valign-top">Schema</th>
|
||||
<th class="tableblock halign-left valign-top">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">maxUnavailable</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The maximum number of DaemonSet pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of total number of DaemonSet pods at the start of the update (ex: 10%). Absolute number is calculated from percentage by rounding up. This cannot be 0. Default value is 1. Example: when this is set to 30%, 30% of the currently running DaemonSet pods can be stopped for an update at any given time. The update starts by stopping at most 30% of the currently running DaemonSet pods and then brings up new DaemonSet pods in their place. Once the new pods are ready, it then proceeds onto other DaemonSet pods, thus ensuring that at least 70% of original number of DaemonSet pods are available at all times during the update.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_objectmeta">v1.ObjectMeta</h3>
|
||||
@ -2131,6 +2186,27 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_podtemplatespec">v1.PodTemplateSpec</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">updateStrategy</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">UpdateStrategy to replace existing DaemonSet pods with new pods.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_daemonsetupdatestrategy">v1beta1.DaemonSetUpdateStrategy</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">minReadySeconds</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">MinReadySeconds minimum number of seconds for which a newly created DaemonSet pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).</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">integer (int32)</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">templateGeneration</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">A sequence number representing a specific generation of the template. Populated by the system. It can be set only during the creation.</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">integer (int64)</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -3221,6 +3297,44 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1beta1_daemonsetupdatestrategy">v1beta1.DaemonSetUpdateStrategy</h3>
|
||||
<table class="tableblock frame-all grid-all" style="width:100%; ">
|
||||
<colgroup>
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tableblock halign-left valign-top">Name</th>
|
||||
<th class="tableblock halign-left valign-top">Description</th>
|
||||
<th class="tableblock halign-left valign-top">Required</th>
|
||||
<th class="tableblock halign-left valign-top">Schema</th>
|
||||
<th class="tableblock halign-left valign-top">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">type</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Type of daemon set update. Can be "RollingUpdate" or "OnDelete". Default is OnDelete.</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">rollingUpdate</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Rolling update config params. Present only if DaemonSetUpdateStrategy = RollingUpdate.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_rollingupdatedaemonset">v1beta1.RollingUpdateDaemonSet</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_vspherevirtualdiskvolumesource">v1.VsphereVirtualDiskVolumeSource</h3>
|
||||
@ -7612,7 +7726,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-02-23 20:32:58 UTC
|
||||
Last updated 2017-02-27 08:17:02 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -13810,6 +13810,11 @@
|
||||
"template"
|
||||
],
|
||||
"properties": {
|
||||
"minReadySeconds": {
|
||||
"description": "MinReadySeconds minimum number of seconds for which a newly created DaemonSet pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"selector": {
|
||||
"description": "Selector is a label query over pods that are managed by the daemon set. Must match in order to be controlled. If empty, defaulted to labels on Pod template. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors",
|
||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector"
|
||||
@ -13817,6 +13822,15 @@
|
||||
"template": {
|
||||
"description": "Template is the object that describes the pod that will be created. The DaemonSet will create exactly one copy of this pod on every node that matches the template's node selector (or on every node if no node selector is specified). More info: http://kubernetes.io/docs/user-guide/replication-controller#pod-template",
|
||||
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.PodTemplateSpec"
|
||||
},
|
||||
"templateGeneration": {
|
||||
"description": "A sequence number representing a specific generation of the template. Populated by the system. It can be set only during the creation.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"updateStrategy": {
|
||||
"description": "UpdateStrategy to replace existing DaemonSet pods with new pods.",
|
||||
"$ref": "#/definitions/io.k8s.kubernetes.pkg.apis.extensions.v1beta1.DaemonSetUpdateStrategy"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -13839,6 +13853,11 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"numberAvailable": {
|
||||
"description": "NumberAvailable is the number of nodes that should be running the daemon pod and have one or more of the daemon pod running and available (ready for at least minReadySeconds)",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"numberMisscheduled": {
|
||||
"description": "NumberMisscheduled is the number of nodes that are running the daemon pod, but are not supposed to run the daemon pod. More info: http://releases.k8s.io/HEAD/docs/admin/daemons.md",
|
||||
"type": "integer",
|
||||
@ -13849,10 +13868,32 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"numberUnavailable": {
|
||||
"description": "NumberUnavailable is the number of nodes that should be running the daemon pod and have none of the daemon pod running and available (ready for at least minReadySeconds)",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"observedGeneration": {
|
||||
"description": "ObservedGeneration is the most recent generation observed by the daemon set controller.",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"updatedNumberScheduled": {
|
||||
"description": "UpdatedNumberScheduled is the total number of nodes that are running updated daemon pod",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
},
|
||||
"io.k8s.kubernetes.pkg.apis.extensions.v1beta1.DaemonSetUpdateStrategy": {
|
||||
"properties": {
|
||||
"rollingUpdate": {
|
||||
"description": "Rolling update config params. Present only if DaemonSetUpdateStrategy = RollingUpdate.",
|
||||
"$ref": "#/definitions/io.k8s.kubernetes.pkg.apis.extensions.v1beta1.RollingUpdateDaemonSet"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type of daemon set update. Can be \"RollingUpdate\" or \"OnDelete\". Default is OnDelete.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -14438,6 +14479,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"io.k8s.kubernetes.pkg.apis.extensions.v1beta1.RollingUpdateDaemonSet": {
|
||||
"description": "Spec to control the desired behavior of daemon set rolling update.",
|
||||
"properties": {
|
||||
"maxUnavailable": {
|
||||
"description": "The maximum number of DaemonSet pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of total number of DaemonSet pods at the start of the update (ex: 10%). Absolute number is calculated from percentage by rounding up. This cannot be 0. Default value is 1. Example: when this is set to 30%, 30% of the currently running DaemonSet pods can be stopped for an update at any given time. The update starts by stopping at most 30% of the currently running DaemonSet pods and then brings up new DaemonSet pods in their place. Once the new pods are ready, it then proceeds onto other DaemonSet pods, thus ensuring that at least 70% of original number of DaemonSet pods are available at all times during the update.",
|
||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString"
|
||||
}
|
||||
}
|
||||
},
|
||||
"io.k8s.kubernetes.pkg.apis.extensions.v1beta1.RollingUpdateDeployment": {
|
||||
"description": "Spec to control the desired behavior of rolling update.",
|
||||
"properties": {
|
||||
|
@ -518,6 +518,25 @@ func extensionFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
}
|
||||
}
|
||||
},
|
||||
func(j *extensions.DaemonSetUpdateStrategy, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
// Ensure that strategyType is one of valid values.
|
||||
strategyTypes := []extensions.DaemonSetUpdateStrategyType{extensions.RollingUpdateDaemonSetStrategyType, extensions.OnDeleteDaemonSetStrategyType}
|
||||
j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))]
|
||||
if j.Type != extensions.RollingUpdateDaemonSetStrategyType {
|
||||
j.RollingUpdate = nil
|
||||
} else {
|
||||
rollingUpdate := extensions.RollingUpdateDaemonSet{}
|
||||
if c.RandBool() {
|
||||
if c.RandBool() {
|
||||
rollingUpdate.MaxUnavailable = intstr.FromInt(1 + int(c.Rand.Int31()))
|
||||
} else {
|
||||
rollingUpdate.MaxUnavailable = intstr.FromString(fmt.Sprintf("%d%%", 1+c.Rand.Int31()))
|
||||
}
|
||||
}
|
||||
j.RollingUpdate = &rollingUpdate
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,11 +370,10 @@ type DeploymentList struct {
|
||||
Items []Deployment
|
||||
}
|
||||
|
||||
// TODO(madhusudancs): Uncomment while implementing DaemonSet updates.
|
||||
/* Commenting out for v1.2. We are planning to bring these types back with a more robust DaemonSet update implementation in v1.3, hence not deleting but just commenting the types out.
|
||||
type DaemonSetUpdateStrategy struct {
|
||||
// Type of daemon set update. Only "RollingUpdate" is supported at this time. Default is RollingUpdate.
|
||||
// +optional
|
||||
// Type of daemon set update. Can be "RollingUpdate" or "OnDelete".
|
||||
// Default is OnDelete.
|
||||
// +optional
|
||||
Type DaemonSetUpdateStrategyType
|
||||
|
||||
// Rolling update config params. Present only if DaemonSetUpdateStrategy =
|
||||
@ -382,7 +381,8 @@ type DaemonSetUpdateStrategy struct {
|
||||
//---
|
||||
// TODO: Update this to follow our convention for oneOf, whatever we decide it
|
||||
// to be. Same as DeploymentStrategy.RollingUpdate.
|
||||
// +optional
|
||||
// See https://github.com/kubernetes/kubernetes/issues/35345
|
||||
// +optional
|
||||
RollingUpdate *RollingUpdateDaemonSet
|
||||
}
|
||||
|
||||
@ -391,6 +391,9 @@ type DaemonSetUpdateStrategyType string
|
||||
const (
|
||||
// Replace the old daemons by new ones using rolling update i.e replace them on each node one after the other.
|
||||
RollingUpdateDaemonSetStrategyType DaemonSetUpdateStrategyType = "RollingUpdate"
|
||||
|
||||
// Replace the old daemons only when it's killed
|
||||
OnDeleteDaemonSetStrategyType DaemonSetUpdateStrategyType = "OnDelete"
|
||||
)
|
||||
|
||||
// Spec to control the desired behavior of daemon set rolling update.
|
||||
@ -408,17 +411,9 @@ type RollingUpdateDaemonSet struct {
|
||||
// it then proceeds onto other DaemonSet pods, thus ensuring that at least
|
||||
// 70% of original number of DaemonSet pods are available at all times
|
||||
// during the update.
|
||||
// +optional
|
||||
// +optional
|
||||
MaxUnavailable intstr.IntOrString
|
||||
|
||||
// Minimum number of seconds for which a newly created DaemonSet pod should
|
||||
// be ready without any of its container crashing, for it to be considered
|
||||
// available. Defaults to 0 (pod will be considered available as soon as it
|
||||
// is ready).
|
||||
// +optional
|
||||
MinReadySeconds int
|
||||
}
|
||||
*/
|
||||
|
||||
// DaemonSetSpec is the specification of a daemon set.
|
||||
type DaemonSetSpec struct {
|
||||
@ -436,31 +431,23 @@ type DaemonSetSpec struct {
|
||||
// More info: http://kubernetes.io/docs/user-guide/replication-controller#pod-template
|
||||
Template api.PodTemplateSpec
|
||||
|
||||
// TODO(madhusudancs): Uncomment while implementing DaemonSet updates.
|
||||
/* Commenting out for v1.2. We are planning to bring these fields back with a more robust DaemonSet update implementation in v1.3, hence not deleting but just commenting these fields out.
|
||||
// Update strategy to replace existing DaemonSet pods with new pods.
|
||||
// UpdateStrategy to replace existing DaemonSet pods with new pods.
|
||||
// +optional
|
||||
UpdateStrategy DaemonSetUpdateStrategy
|
||||
UpdateStrategy DaemonSetUpdateStrategy
|
||||
|
||||
// Label key that is added to DaemonSet pods to distinguish between old and
|
||||
// new pod templates during DaemonSet update.
|
||||
// Users can set this to an empty string to indicate that the system should
|
||||
// not add any label. If unspecified, system uses
|
||||
// DefaultDaemonSetUniqueLabelKey("daemonset.kubernetes.io/podTemplateHash").
|
||||
// Value of this key is hash of DaemonSetSpec.PodTemplateSpec.
|
||||
// No label is added if this is set to empty string.
|
||||
// MinReadySeconds minimum number of seconds for which a newly created DaemonSet pod should
|
||||
// be ready without any of its container crashing, for it to be considered
|
||||
// available. Defaults to 0 (pod will be considered available as soon as it
|
||||
// is ready).
|
||||
// +optional
|
||||
UniqueLabelKey string
|
||||
*/
|
||||
MinReadySeconds int32
|
||||
|
||||
// A sequence number representing a specific generation of the template.
|
||||
// Populated by the system. It can be set only during the creation.
|
||||
// +optional
|
||||
TemplateGeneration int64
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultDaemonSetUniqueLabelKey is the default key of the labels that is added
|
||||
// to daemon set pods to distinguish between old and new pod templates during
|
||||
// DaemonSet update. See DaemonSetSpec's UniqueLabelKey field for more information.
|
||||
DefaultDaemonSetUniqueLabelKey string = "daemonset.kubernetes.io/podTemplateHash"
|
||||
)
|
||||
|
||||
// DaemonSetStatus represents the current status of a daemon set.
|
||||
type DaemonSetStatus struct {
|
||||
// CurrentNumberScheduled is the number of nodes that are running at least 1
|
||||
@ -482,6 +469,23 @@ type DaemonSetStatus struct {
|
||||
// ObservedGeneration is the most recent generation observed by the daemon set controller.
|
||||
// +optional
|
||||
ObservedGeneration int64
|
||||
|
||||
// UpdatedNumberScheduled is the total number of nodes that are running updated
|
||||
// daemon pod
|
||||
// +optional
|
||||
UpdatedNumberScheduled int32
|
||||
|
||||
// NumberAvailable is the number of nodes that should be running the
|
||||
// daemon pod and have one or more of the daemon pod running and
|
||||
// available (ready for at least minReadySeconds)
|
||||
// +optional
|
||||
NumberAvailable int32
|
||||
|
||||
// NumberUnavailable is the number of nodes that should be running the
|
||||
// daemon pod and have none of the daemon pod running and available
|
||||
// (ready for at least minReadySeconds)
|
||||
// +optional
|
||||
NumberUnavailable int32
|
||||
}
|
||||
|
||||
// +genclient=true
|
||||
@ -508,6 +512,13 @@ type DaemonSet struct {
|
||||
Status DaemonSetStatus
|
||||
}
|
||||
|
||||
const (
|
||||
// DaemonSetTemplateGenerationKey is the key of the labels that is added
|
||||
// to daemon set pods to distinguish between old and new pod templates
|
||||
// during DaemonSet template update.
|
||||
DaemonSetTemplateGenerationKey string = "pod-template-generation"
|
||||
)
|
||||
|
||||
// DaemonSetList is a collection of daemon sets.
|
||||
type DaemonSetList struct {
|
||||
metav1.TypeMeta
|
||||
|
@ -38,6 +38,8 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
Convert_v1beta1_DeploymentStrategy_To_extensions_DeploymentStrategy,
|
||||
Convert_extensions_RollingUpdateDeployment_To_v1beta1_RollingUpdateDeployment,
|
||||
Convert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment,
|
||||
Convert_extensions_RollingUpdateDaemonSet_To_v1beta1_RollingUpdateDaemonSet,
|
||||
Convert_v1beta1_RollingUpdateDaemonSet_To_extensions_RollingUpdateDaemonSet,
|
||||
Convert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec,
|
||||
Convert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec,
|
||||
)
|
||||
@ -219,6 +221,23 @@ func Convert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployme
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_extensions_RollingUpdateDaemonSet_To_v1beta1_RollingUpdateDaemonSet(in *extensions.RollingUpdateDaemonSet, out *RollingUpdateDaemonSet, s conversion.Scope) error {
|
||||
if out.MaxUnavailable == nil {
|
||||
out.MaxUnavailable = &intstr.IntOrString{}
|
||||
}
|
||||
if err := s.Convert(&in.MaxUnavailable, out.MaxUnavailable, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1beta1_RollingUpdateDaemonSet_To_extensions_RollingUpdateDaemonSet(in *RollingUpdateDaemonSet, out *extensions.RollingUpdateDaemonSet, s conversion.Scope) error {
|
||||
if err := s.Convert(in.MaxUnavailable, &out.MaxUnavailable, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec(in *extensions.ReplicaSetSpec, out *ReplicaSetSpec, s conversion.Scope) error {
|
||||
out.Replicas = new(int32)
|
||||
*out.Replicas = int32(in.Replicas)
|
||||
|
@ -47,6 +47,21 @@ func SetDefaults_DaemonSet(obj *DaemonSet) {
|
||||
obj.Labels = labels
|
||||
}
|
||||
}
|
||||
updateStrategy := &obj.Spec.UpdateStrategy
|
||||
if updateStrategy.Type == "" {
|
||||
updateStrategy.Type = OnDeleteDaemonSetStrategyType
|
||||
}
|
||||
if updateStrategy.Type == RollingUpdateDaemonSetStrategyType {
|
||||
if updateStrategy.RollingUpdate == nil {
|
||||
rollingUpdate := RollingUpdateDaemonSet{}
|
||||
updateStrategy.RollingUpdate = &rollingUpdate
|
||||
}
|
||||
if updateStrategy.RollingUpdate.MaxUnavailable == nil {
|
||||
// Set default MaxUnavailable as 1 by default.
|
||||
maxUnavailable := intstr.FromInt(1)
|
||||
updateStrategy.RollingUpdate.MaxUnavailable = &maxUnavailable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetDefaults_Deployment(obj *Deployment) {
|
||||
|
@ -74,6 +74,9 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
MatchLabels: defaultLabels,
|
||||
},
|
||||
Template: defaultTemplate,
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -99,6 +102,9 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
MatchLabels: defaultLabels,
|
||||
},
|
||||
Template: defaultTemplate,
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -107,6 +113,9 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
expected: &DaemonSet{
|
||||
Spec: DaemonSetSpec{
|
||||
Template: templateNoLabel,
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -117,6 +126,9 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
expected: &DaemonSet{
|
||||
Spec: DaemonSetSpec{
|
||||
Template: templateNoLabel,
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -127,6 +139,9 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
expected: &DaemonSet{
|
||||
Spec: DaemonSetSpec{
|
||||
Template: templateNoLabel,
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -111,6 +111,22 @@ message DaemonSetSpec {
|
||||
// selector is specified).
|
||||
// More info: http://kubernetes.io/docs/user-guide/replication-controller#pod-template
|
||||
optional k8s.io.kubernetes.pkg.api.v1.PodTemplateSpec template = 2;
|
||||
|
||||
// UpdateStrategy to replace existing DaemonSet pods with new pods.
|
||||
// +optional
|
||||
optional DaemonSetUpdateStrategy updateStrategy = 3;
|
||||
|
||||
// MinReadySeconds minimum number of seconds for which a newly created DaemonSet pod should
|
||||
// be ready without any of its container crashing, for it to be considered
|
||||
// available. Defaults to 0 (pod will be considered available as soon as it
|
||||
// is ready).
|
||||
// +optional
|
||||
optional int32 minReadySeconds = 4;
|
||||
|
||||
// A sequence number representing a specific generation of the template.
|
||||
// Populated by the system. It can be set only during the creation.
|
||||
// +optional
|
||||
optional int64 templateGeneration = 5;
|
||||
}
|
||||
|
||||
// DaemonSetStatus represents the current status of a daemon set.
|
||||
@ -137,6 +153,39 @@ message DaemonSetStatus {
|
||||
// ObservedGeneration is the most recent generation observed by the daemon set controller.
|
||||
// +optional
|
||||
optional int64 observedGeneration = 5;
|
||||
|
||||
// UpdatedNumberScheduled is the total number of nodes that are running updated
|
||||
// daemon pod
|
||||
// +optional
|
||||
optional int32 updatedNumberScheduled = 6;
|
||||
|
||||
// NumberAvailable is the number of nodes that should be running the
|
||||
// daemon pod and have one or more of the daemon pod running and
|
||||
// available (ready for at least minReadySeconds)
|
||||
// +optional
|
||||
optional int32 numberAvailable = 7;
|
||||
|
||||
// NumberUnavailable is the number of nodes that should be running the
|
||||
// daemon pod and have none of the daemon pod running and available
|
||||
// (ready for at least minReadySeconds)
|
||||
// +optional
|
||||
optional int32 numberUnavailable = 8;
|
||||
}
|
||||
|
||||
message DaemonSetUpdateStrategy {
|
||||
// Type of daemon set update. Can be "RollingUpdate" or "OnDelete".
|
||||
// Default is OnDelete.
|
||||
// +optional
|
||||
optional string type = 1;
|
||||
|
||||
// Rolling update config params. Present only if DaemonSetUpdateStrategy =
|
||||
// RollingUpdate.
|
||||
// ---
|
||||
// TODO: Update this to follow our convention for oneOf, whatever we decide it
|
||||
// to be. Same as DeploymentStrategy.RollingUpdate.
|
||||
// See https://github.com/kubernetes/kubernetes/issues/35345
|
||||
// +optional
|
||||
optional RollingUpdateDaemonSet rollingUpdate = 2;
|
||||
}
|
||||
|
||||
// Deployment enables declarative updates for Pods and ReplicaSets.
|
||||
@ -784,6 +833,25 @@ message RollbackConfig {
|
||||
optional int64 revision = 1;
|
||||
}
|
||||
|
||||
// Spec to control the desired behavior of daemon set rolling update.
|
||||
message RollingUpdateDaemonSet {
|
||||
// The maximum number of DaemonSet pods that can be unavailable during the
|
||||
// update. Value can be an absolute number (ex: 5) or a percentage of total
|
||||
// number of DaemonSet pods at the start of the update (ex: 10%). Absolute
|
||||
// number is calculated from percentage by rounding up.
|
||||
// This cannot be 0.
|
||||
// Default value is 1.
|
||||
// Example: when this is set to 30%, 30% of the currently running DaemonSet
|
||||
// pods can be stopped for an update at any given time. The update starts
|
||||
// by stopping at most 30% of the currently running DaemonSet pods and then
|
||||
// brings up new DaemonSet pods in their place. Once the new pods are ready,
|
||||
// it then proceeds onto other DaemonSet pods, thus ensuring that at least
|
||||
// 70% of original number of DaemonSet pods are available at all times
|
||||
// during the update.
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 1;
|
||||
}
|
||||
|
||||
// Spec to control the desired behavior of rolling update.
|
||||
message RollingUpdateDeployment {
|
||||
// The maximum number of pods that can be unavailable during the update.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -369,20 +369,20 @@ type DeploymentList struct {
|
||||
Items []Deployment `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// TODO(madhusudancs): Uncomment while implementing DaemonSet updates.
|
||||
/* Commenting out for v1.2. We are planning to bring these types back with a more robust DaemonSet update implementation in v1.3, hence not deleting but just commenting the types out.
|
||||
type DaemonSetUpdateStrategy struct {
|
||||
// Type of daemon set update. Only "RollingUpdate" is supported at this time. Default is RollingUpdate.
|
||||
// +optional
|
||||
Type DaemonSetUpdateStrategyType `json:"type,omitempty"`
|
||||
// Type of daemon set update. Can be "RollingUpdate" or "OnDelete".
|
||||
// Default is OnDelete.
|
||||
// +optional
|
||||
Type DaemonSetUpdateStrategyType `json:"type,omitempty" protobuf:"bytes,1,opt,name=type"`
|
||||
|
||||
// Rolling update config params. Present only if DaemonSetUpdateStrategy =
|
||||
// RollingUpdate.
|
||||
//---
|
||||
// TODO: Update this to follow our convention for oneOf, whatever we decide it
|
||||
// to be. Same as DeploymentStrategy.RollingUpdate.
|
||||
// +optional
|
||||
RollingUpdate *RollingUpdateDaemonSet `json:"rollingUpdate,omitempty"`
|
||||
// See https://github.com/kubernetes/kubernetes/issues/35345
|
||||
// +optional
|
||||
RollingUpdate *RollingUpdateDaemonSet `json:"rollingUpdate,omitempty" protobuf:"bytes,2,opt,name=rollingUpdate"`
|
||||
}
|
||||
|
||||
type DaemonSetUpdateStrategyType string
|
||||
@ -390,6 +390,9 @@ type DaemonSetUpdateStrategyType string
|
||||
const (
|
||||
// Replace the old daemons by new ones using rolling update i.e replace them on each node one after the other.
|
||||
RollingUpdateDaemonSetStrategyType DaemonSetUpdateStrategyType = "RollingUpdate"
|
||||
|
||||
// Replace the old daemons only when it's killed
|
||||
OnDeleteDaemonSetStrategyType DaemonSetUpdateStrategyType = "OnDelete"
|
||||
)
|
||||
|
||||
// Spec to control the desired behavior of daemon set rolling update.
|
||||
@ -407,17 +410,9 @@ type RollingUpdateDaemonSet struct {
|
||||
// it then proceeds onto other DaemonSet pods, thus ensuring that at least
|
||||
// 70% of original number of DaemonSet pods are available at all times
|
||||
// during the update.
|
||||
// +optional
|
||||
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
|
||||
|
||||
// Minimum number of seconds for which a newly created DaemonSet pod should
|
||||
// be ready without any of its container crashing, for it to be considered
|
||||
// available. Defaults to 0 (pod will be considered available as soon as it
|
||||
// is ready).
|
||||
// +optional
|
||||
MinReadySeconds int32 `json:"minReadySeconds,omitempty"`
|
||||
// +optional
|
||||
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"bytes,1,opt,name=maxUnavailable"`
|
||||
}
|
||||
*/
|
||||
|
||||
// DaemonSetSpec is the specification of a daemon set.
|
||||
type DaemonSetSpec struct {
|
||||
@ -435,31 +430,23 @@ type DaemonSetSpec struct {
|
||||
// More info: http://kubernetes.io/docs/user-guide/replication-controller#pod-template
|
||||
Template v1.PodTemplateSpec `json:"template" protobuf:"bytes,2,opt,name=template"`
|
||||
|
||||
// TODO(madhusudancs): Uncomment while implementing DaemonSet updates.
|
||||
/* Commenting out for v1.2. We are planning to bring these fields back with a more robust DaemonSet update implementation in v1.3, hence not deleting but just commenting these fields out.
|
||||
// Update strategy to replace existing DaemonSet pods with new pods.
|
||||
// UpdateStrategy to replace existing DaemonSet pods with new pods.
|
||||
// +optional
|
||||
UpdateStrategy DaemonSetUpdateStrategy `json:"updateStrategy,omitempty"`
|
||||
UpdateStrategy DaemonSetUpdateStrategy `json:"updateStrategy,omitempty" protobuf:"bytes,3,opt,name=updateStrategy"`
|
||||
|
||||
// Label key that is added to DaemonSet pods to distinguish between old and
|
||||
// new pod templates during DaemonSet update.
|
||||
// Users can set this to an empty string to indicate that the system should
|
||||
// not add any label. If unspecified, system uses
|
||||
// DefaultDaemonSetUniqueLabelKey("daemonset.kubernetes.io/podTemplateHash").
|
||||
// Value of this key is hash of DaemonSetSpec.PodTemplateSpec.
|
||||
// No label is added if this is set to empty string.
|
||||
// MinReadySeconds minimum number of seconds for which a newly created DaemonSet pod should
|
||||
// be ready without any of its container crashing, for it to be considered
|
||||
// available. Defaults to 0 (pod will be considered available as soon as it
|
||||
// is ready).
|
||||
// +optional
|
||||
UniqueLabelKey *string `json:"uniqueLabelKey,omitempty"`
|
||||
*/
|
||||
MinReadySeconds int32 `json:"minReadySeconds,omitempty" protobuf:"varint,4,opt,name=minReadySeconds"`
|
||||
|
||||
// A sequence number representing a specific generation of the template.
|
||||
// Populated by the system. It can be set only during the creation.
|
||||
// +optional
|
||||
TemplateGeneration int64 `json:"templateGeneration,omitempty" protobuf:"varint,5,opt,name=templateGeneration"`
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultDaemonSetUniqueLabelKey is the default key of the labels that is added
|
||||
// to daemon set pods to distinguish between old and new pod templates during
|
||||
// DaemonSet update. See DaemonSetSpec's UniqueLabelKey field for more information.
|
||||
DefaultDaemonSetUniqueLabelKey string = "daemonset.kubernetes.io/podTemplateHash"
|
||||
)
|
||||
|
||||
// DaemonSetStatus represents the current status of a daemon set.
|
||||
type DaemonSetStatus struct {
|
||||
// CurrentNumberScheduled is the number of nodes that are running at least 1
|
||||
@ -484,6 +471,23 @@ type DaemonSetStatus struct {
|
||||
// ObservedGeneration is the most recent generation observed by the daemon set controller.
|
||||
// +optional
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty" protobuf:"varint,5,opt,name=observedGeneration"`
|
||||
|
||||
// UpdatedNumberScheduled is the total number of nodes that are running updated
|
||||
// daemon pod
|
||||
// +optional
|
||||
UpdatedNumberScheduled int32 `json:"updatedNumberScheduled,omitempty" protobuf:"varint,6,opt,name=updatedNumberScheduled"`
|
||||
|
||||
// NumberAvailable is the number of nodes that should be running the
|
||||
// daemon pod and have one or more of the daemon pod running and
|
||||
// available (ready for at least minReadySeconds)
|
||||
// +optional
|
||||
NumberAvailable int32 `json:"numberAvailable,omitempty" protobuf:"varint,7,opt,name=numberAvailable"`
|
||||
|
||||
// NumberUnavailable is the number of nodes that should be running the
|
||||
// daemon pod and have none of the daemon pod running and available
|
||||
// (ready for at least minReadySeconds)
|
||||
// +optional
|
||||
NumberUnavailable int32 `json:"numberUnavailable,omitempty" protobuf:"varint,8,opt,name=numberUnavailable"`
|
||||
}
|
||||
|
||||
// +genclient=true
|
||||
@ -510,6 +514,13 @@ type DaemonSet struct {
|
||||
Status DaemonSetStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
const (
|
||||
// DaemonSetTemplateGenerationKey is the key of the labels that is added
|
||||
// to daemon set pods to distinguish between old and new pod templates
|
||||
// during DaemonSet template update.
|
||||
DaemonSetTemplateGenerationKey string = "pod-template-generation"
|
||||
)
|
||||
|
||||
// DaemonSetList is a collection of daemon sets.
|
||||
type DaemonSetList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
@ -77,9 +77,12 @@ func (DaemonSetList) SwaggerDoc() map[string]string {
|
||||
}
|
||||
|
||||
var map_DaemonSetSpec = map[string]string{
|
||||
"": "DaemonSetSpec is the specification of a daemon set.",
|
||||
"selector": "Selector is a label query over pods that are managed by the daemon set. Must match in order to be controlled. If empty, defaulted to labels on Pod template. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors",
|
||||
"template": "Template is the object that describes the pod that will be created. The DaemonSet will create exactly one copy of this pod on every node that matches the template's node selector (or on every node if no node selector is specified). More info: http://kubernetes.io/docs/user-guide/replication-controller#pod-template",
|
||||
"": "DaemonSetSpec is the specification of a daemon set.",
|
||||
"selector": "Selector is a label query over pods that are managed by the daemon set. Must match in order to be controlled. If empty, defaulted to labels on Pod template. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors",
|
||||
"template": "Template is the object that describes the pod that will be created. The DaemonSet will create exactly one copy of this pod on every node that matches the template's node selector (or on every node if no node selector is specified). More info: http://kubernetes.io/docs/user-guide/replication-controller#pod-template",
|
||||
"updateStrategy": "UpdateStrategy to replace existing DaemonSet pods with new pods.",
|
||||
"minReadySeconds": "MinReadySeconds minimum number of seconds for which a newly created DaemonSet pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).",
|
||||
"templateGeneration": "A sequence number representing a specific generation of the template. Populated by the system. It can be set only during the creation.",
|
||||
}
|
||||
|
||||
func (DaemonSetSpec) SwaggerDoc() map[string]string {
|
||||
@ -93,12 +96,24 @@ var map_DaemonSetStatus = map[string]string{
|
||||
"desiredNumberScheduled": "DesiredNumberScheduled is the total number of nodes that should be running the daemon pod (including nodes correctly running the daemon pod). More info: http://releases.k8s.io/HEAD/docs/admin/daemons.md",
|
||||
"numberReady": "NumberReady is the number of nodes that should be running the daemon pod and have one or more of the daemon pod running and ready.",
|
||||
"observedGeneration": "ObservedGeneration is the most recent generation observed by the daemon set controller.",
|
||||
"updatedNumberScheduled": "UpdatedNumberScheduled is the total number of nodes that are running updated daemon pod",
|
||||
"numberAvailable": "NumberAvailable is the number of nodes that should be running the daemon pod and have one or more of the daemon pod running and available (ready for at least minReadySeconds)",
|
||||
"numberUnavailable": "NumberUnavailable is the number of nodes that should be running the daemon pod and have none of the daemon pod running and available (ready for at least minReadySeconds)",
|
||||
}
|
||||
|
||||
func (DaemonSetStatus) SwaggerDoc() map[string]string {
|
||||
return map_DaemonSetStatus
|
||||
}
|
||||
|
||||
var map_DaemonSetUpdateStrategy = map[string]string{
|
||||
"type": "Type of daemon set update. Can be \"RollingUpdate\" or \"OnDelete\". Default is OnDelete.",
|
||||
"rollingUpdate": "Rolling update config params. Present only if DaemonSetUpdateStrategy = RollingUpdate.",
|
||||
}
|
||||
|
||||
func (DaemonSetUpdateStrategy) SwaggerDoc() map[string]string {
|
||||
return map_DaemonSetUpdateStrategy
|
||||
}
|
||||
|
||||
var map_Deployment = map[string]string{
|
||||
"": "Deployment enables declarative updates for Pods and ReplicaSets.",
|
||||
"metadata": "Standard object metadata.",
|
||||
@ -488,6 +503,15 @@ func (RollbackConfig) SwaggerDoc() map[string]string {
|
||||
return map_RollbackConfig
|
||||
}
|
||||
|
||||
var map_RollingUpdateDaemonSet = map[string]string{
|
||||
"": "Spec to control the desired behavior of daemon set rolling update.",
|
||||
"maxUnavailable": "The maximum number of DaemonSet pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of total number of DaemonSet pods at the start of the update (ex: 10%). Absolute number is calculated from percentage by rounding up. This cannot be 0. Default value is 1. Example: when this is set to 30%, 30% of the currently running DaemonSet pods can be stopped for an update at any given time. The update starts by stopping at most 30% of the currently running DaemonSet pods and then brings up new DaemonSet pods in their place. Once the new pods are ready, it then proceeds onto other DaemonSet pods, thus ensuring that at least 70% of original number of DaemonSet pods are available at all times during the update.",
|
||||
}
|
||||
|
||||
func (RollingUpdateDaemonSet) SwaggerDoc() map[string]string {
|
||||
return map_RollingUpdateDaemonSet
|
||||
}
|
||||
|
||||
var map_RollingUpdateDeployment = map[string]string{
|
||||
"": "Spec to control the desired behavior of rolling update.",
|
||||
"maxUnavailable": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. By default, a fixed value of 1 is used. Example: when this is set to 30%, the old RC can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old RC can be scaled down further, followed by scaling up the new RC, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods.",
|
||||
|
@ -57,6 +57,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
Convert_extensions_DaemonSetSpec_To_v1beta1_DaemonSetSpec,
|
||||
Convert_v1beta1_DaemonSetStatus_To_extensions_DaemonSetStatus,
|
||||
Convert_extensions_DaemonSetStatus_To_v1beta1_DaemonSetStatus,
|
||||
Convert_v1beta1_DaemonSetUpdateStrategy_To_extensions_DaemonSetUpdateStrategy,
|
||||
Convert_extensions_DaemonSetUpdateStrategy_To_v1beta1_DaemonSetUpdateStrategy,
|
||||
Convert_v1beta1_Deployment_To_extensions_Deployment,
|
||||
Convert_extensions_Deployment_To_v1beta1_Deployment,
|
||||
Convert_v1beta1_DeploymentCondition_To_extensions_DeploymentCondition,
|
||||
@ -129,6 +131,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
Convert_extensions_ReplicationControllerDummy_To_v1beta1_ReplicationControllerDummy,
|
||||
Convert_v1beta1_RollbackConfig_To_extensions_RollbackConfig,
|
||||
Convert_extensions_RollbackConfig_To_v1beta1_RollbackConfig,
|
||||
Convert_v1beta1_RollingUpdateDaemonSet_To_extensions_RollingUpdateDaemonSet,
|
||||
Convert_extensions_RollingUpdateDaemonSet_To_v1beta1_RollingUpdateDaemonSet,
|
||||
Convert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment,
|
||||
Convert_extensions_RollingUpdateDeployment_To_v1beta1_RollingUpdateDeployment,
|
||||
Convert_v1beta1_RunAsUserStrategyOptions_To_extensions_RunAsUserStrategyOptions,
|
||||
@ -323,6 +327,11 @@ func autoConvert_v1beta1_DaemonSetSpec_To_extensions_DaemonSetSpec(in *DaemonSet
|
||||
if err := api_v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1beta1_DaemonSetUpdateStrategy_To_extensions_DaemonSetUpdateStrategy(&in.UpdateStrategy, &out.UpdateStrategy, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.MinReadySeconds = in.MinReadySeconds
|
||||
out.TemplateGeneration = in.TemplateGeneration
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -335,6 +344,11 @@ func autoConvert_extensions_DaemonSetSpec_To_v1beta1_DaemonSetSpec(in *extension
|
||||
if err := api_v1.Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_extensions_DaemonSetUpdateStrategy_To_v1beta1_DaemonSetUpdateStrategy(&in.UpdateStrategy, &out.UpdateStrategy, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.MinReadySeconds = in.MinReadySeconds
|
||||
out.TemplateGeneration = in.TemplateGeneration
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -348,6 +362,9 @@ func autoConvert_v1beta1_DaemonSetStatus_To_extensions_DaemonSetStatus(in *Daemo
|
||||
out.DesiredNumberScheduled = in.DesiredNumberScheduled
|
||||
out.NumberReady = in.NumberReady
|
||||
out.ObservedGeneration = in.ObservedGeneration
|
||||
out.UpdatedNumberScheduled = in.UpdatedNumberScheduled
|
||||
out.NumberAvailable = in.NumberAvailable
|
||||
out.NumberUnavailable = in.NumberUnavailable
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -361,6 +378,9 @@ func autoConvert_extensions_DaemonSetStatus_To_v1beta1_DaemonSetStatus(in *exten
|
||||
out.DesiredNumberScheduled = in.DesiredNumberScheduled
|
||||
out.NumberReady = in.NumberReady
|
||||
out.ObservedGeneration = in.ObservedGeneration
|
||||
out.UpdatedNumberScheduled = in.UpdatedNumberScheduled
|
||||
out.NumberAvailable = in.NumberAvailable
|
||||
out.NumberUnavailable = in.NumberUnavailable
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -368,6 +388,42 @@ func Convert_extensions_DaemonSetStatus_To_v1beta1_DaemonSetStatus(in *extension
|
||||
return autoConvert_extensions_DaemonSetStatus_To_v1beta1_DaemonSetStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_DaemonSetUpdateStrategy_To_extensions_DaemonSetUpdateStrategy(in *DaemonSetUpdateStrategy, out *extensions.DaemonSetUpdateStrategy, s conversion.Scope) error {
|
||||
out.Type = extensions.DaemonSetUpdateStrategyType(in.Type)
|
||||
if in.RollingUpdate != nil {
|
||||
in, out := &in.RollingUpdate, &out.RollingUpdate
|
||||
*out = new(extensions.RollingUpdateDaemonSet)
|
||||
if err := Convert_v1beta1_RollingUpdateDaemonSet_To_extensions_RollingUpdateDaemonSet(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.RollingUpdate = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1beta1_DaemonSetUpdateStrategy_To_extensions_DaemonSetUpdateStrategy(in *DaemonSetUpdateStrategy, out *extensions.DaemonSetUpdateStrategy, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_DaemonSetUpdateStrategy_To_extensions_DaemonSetUpdateStrategy(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_extensions_DaemonSetUpdateStrategy_To_v1beta1_DaemonSetUpdateStrategy(in *extensions.DaemonSetUpdateStrategy, out *DaemonSetUpdateStrategy, s conversion.Scope) error {
|
||||
out.Type = DaemonSetUpdateStrategyType(in.Type)
|
||||
if in.RollingUpdate != nil {
|
||||
in, out := &in.RollingUpdate, &out.RollingUpdate
|
||||
*out = new(RollingUpdateDaemonSet)
|
||||
if err := Convert_extensions_RollingUpdateDaemonSet_To_v1beta1_RollingUpdateDaemonSet(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.RollingUpdate = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_extensions_DaemonSetUpdateStrategy_To_v1beta1_DaemonSetUpdateStrategy(in *extensions.DaemonSetUpdateStrategy, out *DaemonSetUpdateStrategy, s conversion.Scope) error {
|
||||
return autoConvert_extensions_DaemonSetUpdateStrategy_To_v1beta1_DaemonSetUpdateStrategy(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_Deployment_To_extensions_Deployment(in *Deployment, out *extensions.Deployment, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
if err := Convert_v1beta1_DeploymentSpec_To_extensions_DeploymentSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
@ -1318,6 +1374,16 @@ func Convert_extensions_RollbackConfig_To_v1beta1_RollbackConfig(in *extensions.
|
||||
return autoConvert_extensions_RollbackConfig_To_v1beta1_RollbackConfig(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_RollingUpdateDaemonSet_To_extensions_RollingUpdateDaemonSet(in *RollingUpdateDaemonSet, out *extensions.RollingUpdateDaemonSet, s conversion.Scope) error {
|
||||
// WARNING: in.MaxUnavailable requires manual conversion: inconvertible types (*k8s.io/apimachinery/pkg/util/intstr.IntOrString vs k8s.io/apimachinery/pkg/util/intstr.IntOrString)
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_extensions_RollingUpdateDaemonSet_To_v1beta1_RollingUpdateDaemonSet(in *extensions.RollingUpdateDaemonSet, out *RollingUpdateDaemonSet, s conversion.Scope) error {
|
||||
// WARNING: in.MaxUnavailable requires manual conversion: inconvertible types (k8s.io/apimachinery/pkg/util/intstr.IntOrString vs *k8s.io/apimachinery/pkg/util/intstr.IntOrString)
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment(in *RollingUpdateDeployment, out *extensions.RollingUpdateDeployment, s conversion.Scope) error {
|
||||
// WARNING: in.MaxUnavailable requires manual conversion: inconvertible types (*k8s.io/apimachinery/pkg/util/intstr.IntOrString vs k8s.io/apimachinery/pkg/util/intstr.IntOrString)
|
||||
// WARNING: in.MaxSurge requires manual conversion: inconvertible types (*k8s.io/apimachinery/pkg/util/intstr.IntOrString vs k8s.io/apimachinery/pkg/util/intstr.IntOrString)
|
||||
|
@ -46,6 +46,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_DaemonSetList, InType: reflect.TypeOf(&DaemonSetList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_DaemonSetSpec, InType: reflect.TypeOf(&DaemonSetSpec{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_DaemonSetStatus, InType: reflect.TypeOf(&DaemonSetStatus{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_DaemonSetUpdateStrategy, InType: reflect.TypeOf(&DaemonSetUpdateStrategy{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_Deployment, InType: reflect.TypeOf(&Deployment{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_DeploymentCondition, InType: reflect.TypeOf(&DeploymentCondition{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_DeploymentList, InType: reflect.TypeOf(&DeploymentList{})},
|
||||
@ -82,6 +83,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_ReplicaSetStatus, InType: reflect.TypeOf(&ReplicaSetStatus{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_ReplicationControllerDummy, InType: reflect.TypeOf(&ReplicationControllerDummy{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_RollbackConfig, InType: reflect.TypeOf(&RollbackConfig{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_RollingUpdateDaemonSet, InType: reflect.TypeOf(&RollingUpdateDaemonSet{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_RollingUpdateDeployment, InType: reflect.TypeOf(&RollingUpdateDeployment{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_RunAsUserStrategyOptions, InType: reflect.TypeOf(&RunAsUserStrategyOptions{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_SELinuxStrategyOptions, InType: reflect.TypeOf(&SELinuxStrategyOptions{})},
|
||||
@ -212,6 +214,9 @@ func DeepCopy_v1beta1_DaemonSetSpec(in interface{}, out interface{}, c *conversi
|
||||
if err := api_v1.DeepCopy_v1_PodTemplateSpec(&in.Template, &out.Template, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_v1beta1_DaemonSetUpdateStrategy(&in.UpdateStrategy, &out.UpdateStrategy, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -225,6 +230,22 @@ func DeepCopy_v1beta1_DaemonSetStatus(in interface{}, out interface{}, c *conver
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_v1beta1_DaemonSetUpdateStrategy(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*DaemonSetUpdateStrategy)
|
||||
out := out.(*DaemonSetUpdateStrategy)
|
||||
*out = *in
|
||||
if in.RollingUpdate != nil {
|
||||
in, out := &in.RollingUpdate, &out.RollingUpdate
|
||||
*out = new(RollingUpdateDaemonSet)
|
||||
if err := DeepCopy_v1beta1_RollingUpdateDaemonSet(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_v1beta1_Deployment(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*Deployment)
|
||||
@ -874,6 +895,20 @@ func DeepCopy_v1beta1_RollbackConfig(in interface{}, out interface{}, c *convers
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_v1beta1_RollingUpdateDaemonSet(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*RollingUpdateDaemonSet)
|
||||
out := out.(*RollingUpdateDaemonSet)
|
||||
*out = *in
|
||||
if in.MaxUnavailable != nil {
|
||||
in, out := &in.MaxUnavailable, &out.MaxUnavailable
|
||||
*out = new(intstr.IntOrString)
|
||||
**out = **in
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_v1beta1_RollingUpdateDeployment(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*RollingUpdateDeployment)
|
||||
|
@ -110,6 +110,9 @@ func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *field.
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DesiredNumberScheduled), fldPath.Child("desiredNumberScheduled"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberReady), fldPath.Child("numberReady"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(status.ObservedGeneration, fldPath.Child("observedGeneration"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.UpdatedNumberScheduled), fldPath.Child("updatedNumberScheduled"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberAvailable), fldPath.Child("numberAvailable"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberUnavailable), fldPath.Child("numberUnavailable"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@ -141,6 +144,40 @@ func ValidateDaemonSetSpec(spec *extensions.DaemonSetSpec, fldPath *field.Path)
|
||||
if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)}))
|
||||
}
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.MinReadySeconds), fldPath.Child("minReadySeconds"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.TemplateGeneration), fldPath.Child("templateGeneration"))...)
|
||||
|
||||
allErrs = append(allErrs, ValidateDaemonSetUpdateStrategy(&spec.UpdateStrategy, fldPath.Child("updateStrategy"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateRollingUpdateDaemonSet(rollingUpdate *extensions.RollingUpdateDaemonSet, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, ValidatePositiveIntOrPercent(rollingUpdate.MaxUnavailable, fldPath.Child("maxUnavailable"))...)
|
||||
if getIntOrPercentValue(rollingUpdate.MaxUnavailable) == 0 {
|
||||
// MaxUnavailable cannot be 0.
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("maxUnavailable"), rollingUpdate.MaxUnavailable, "cannot be 0"))
|
||||
}
|
||||
// Validate that MaxUnavailable is not more than 100%.
|
||||
allErrs = append(allErrs, IsNotMoreThan100Percent(rollingUpdate.MaxUnavailable, fldPath.Child("maxUnavailable"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateDaemonSetUpdateStrategy(strategy *extensions.DaemonSetUpdateStrategy, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
switch strategy.Type {
|
||||
case extensions.OnDeleteDaemonSetStrategyType:
|
||||
case extensions.RollingUpdateDaemonSetStrategyType:
|
||||
// Make sure RollingUpdate field isn't nil.
|
||||
if strategy.RollingUpdate == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("rollingUpdate"), ""))
|
||||
return allErrs
|
||||
}
|
||||
allErrs = append(allErrs, ValidateRollingUpdateDaemonSet(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...)
|
||||
default:
|
||||
validValues := []string{string(extensions.RollingUpdateDaemonSetStrategyType), string(extensions.OnDeleteDaemonSetStrategyType)}
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath, strategy, validValues))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
NumberMisscheduled: 2,
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -55,6 +58,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
NumberMisscheduled: 1,
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -81,6 +87,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -95,6 +104,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: -3,
|
||||
NumberReady: -1,
|
||||
ObservedGeneration: -3,
|
||||
UpdatedNumberScheduled: -1,
|
||||
NumberAvailable: -1,
|
||||
NumberUnavailable: -2,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -111,6 +123,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -125,6 +140,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -141,6 +159,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -155,6 +176,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -171,6 +195,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -185,6 +212,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: -3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -201,6 +231,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -215,6 +248,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: -1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -231,6 +267,9 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -245,6 +284,117 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: -3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative UpdatedNumberScheduled": {
|
||||
old: extensions.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "abc",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
ResourceVersion: "10",
|
||||
},
|
||||
Status: extensions.DaemonSetStatus{
|
||||
CurrentNumberScheduled: 1,
|
||||
NumberMisscheduled: 2,
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "abc",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
ResourceVersion: "10",
|
||||
},
|
||||
Status: extensions.DaemonSetStatus{
|
||||
CurrentNumberScheduled: 1,
|
||||
NumberMisscheduled: 1,
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: -1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative NumberAvailable": {
|
||||
old: extensions.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "abc",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
ResourceVersion: "10",
|
||||
},
|
||||
Status: extensions.DaemonSetStatus{
|
||||
CurrentNumberScheduled: 1,
|
||||
NumberMisscheduled: 2,
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "abc",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
ResourceVersion: "10",
|
||||
},
|
||||
Status: extensions.DaemonSetStatus{
|
||||
CurrentNumberScheduled: 1,
|
||||
NumberMisscheduled: 1,
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: -1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative NumberUnavailable": {
|
||||
old: extensions.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "abc",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
ResourceVersion: "10",
|
||||
},
|
||||
Status: extensions.DaemonSetStatus{
|
||||
CurrentNumberScheduled: 1,
|
||||
NumberMisscheduled: 2,
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: 2,
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "abc",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
ResourceVersion: "10",
|
||||
},
|
||||
Status: extensions.DaemonSetStatus{
|
||||
CurrentNumberScheduled: 1,
|
||||
NumberMisscheduled: 1,
|
||||
DesiredNumberScheduled: 3,
|
||||
NumberReady: 1,
|
||||
ObservedGeneration: 3,
|
||||
UpdatedNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
NumberUnavailable: -2,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -349,6 +499,9 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplateAbc.Template,
|
||||
UpdateStrategy: extensions.DaemonSetUpdateStrategy{
|
||||
Type: extensions.OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -356,6 +509,9 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplateAbc.Template,
|
||||
UpdateStrategy: extensions.DaemonSetUpdateStrategy{
|
||||
Type: extensions.OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -365,6 +521,9 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplateAbc.Template,
|
||||
UpdateStrategy: extensions.DaemonSetUpdateStrategy{
|
||||
Type: extensions.OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -372,6 +531,9 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: validSelector2},
|
||||
Template: validPodTemplateAbc2.Template,
|
||||
UpdateStrategy: extensions.DaemonSetUpdateStrategy{
|
||||
Type: extensions.OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -381,6 +543,9 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplateAbc.Template,
|
||||
UpdateStrategy: extensions.DaemonSetUpdateStrategy{
|
||||
Type: extensions.OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
update: extensions.DaemonSet{
|
||||
@ -388,6 +553,9 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplateNodeSelector.Template,
|
||||
UpdateStrategy: extensions.DaemonSetUpdateStrategy{
|
||||
Type: extensions.OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -536,6 +704,9 @@ func TestValidateDaemonSet(t *testing.T) {
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplate.Template,
|
||||
UpdateStrategy: extensions.DaemonSetUpdateStrategy{
|
||||
Type: extensions.OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -543,6 +714,9 @@ func TestValidateDaemonSet(t *testing.T) {
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplate.Template,
|
||||
UpdateStrategy: extensions.DaemonSetUpdateStrategy{
|
||||
Type: extensions.OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_DaemonSetList, InType: reflect.TypeOf(&DaemonSetList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_DaemonSetSpec, InType: reflect.TypeOf(&DaemonSetSpec{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_DaemonSetStatus, InType: reflect.TypeOf(&DaemonSetStatus{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_DaemonSetUpdateStrategy, InType: reflect.TypeOf(&DaemonSetUpdateStrategy{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_Deployment, InType: reflect.TypeOf(&Deployment{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_DeploymentCondition, InType: reflect.TypeOf(&DeploymentCondition{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_DeploymentList, InType: reflect.TypeOf(&DeploymentList{})},
|
||||
@ -82,6 +83,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ReplicaSetStatus, InType: reflect.TypeOf(&ReplicaSetStatus{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ReplicationControllerDummy, InType: reflect.TypeOf(&ReplicationControllerDummy{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_RollbackConfig, InType: reflect.TypeOf(&RollbackConfig{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_RollingUpdateDaemonSet, InType: reflect.TypeOf(&RollingUpdateDaemonSet{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_RollingUpdateDeployment, InType: reflect.TypeOf(&RollingUpdateDeployment{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_RunAsUserStrategyOptions, InType: reflect.TypeOf(&RunAsUserStrategyOptions{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_SELinuxStrategyOptions, InType: reflect.TypeOf(&SELinuxStrategyOptions{})},
|
||||
@ -212,6 +214,9 @@ func DeepCopy_extensions_DaemonSetSpec(in interface{}, out interface{}, c *conve
|
||||
if err := api.DeepCopy_api_PodTemplateSpec(&in.Template, &out.Template, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_extensions_DaemonSetUpdateStrategy(&in.UpdateStrategy, &out.UpdateStrategy, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -225,6 +230,20 @@ func DeepCopy_extensions_DaemonSetStatus(in interface{}, out interface{}, c *con
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_extensions_DaemonSetUpdateStrategy(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*DaemonSetUpdateStrategy)
|
||||
out := out.(*DaemonSetUpdateStrategy)
|
||||
*out = *in
|
||||
if in.RollingUpdate != nil {
|
||||
in, out := &in.RollingUpdate, &out.RollingUpdate
|
||||
*out = new(RollingUpdateDaemonSet)
|
||||
**out = **in
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_extensions_Deployment(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*Deployment)
|
||||
@ -862,6 +881,15 @@ func DeepCopy_extensions_RollbackConfig(in interface{}, out interface{}, c *conv
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_extensions_RollingUpdateDaemonSet(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*RollingUpdateDaemonSet)
|
||||
out := out.(*RollingUpdateDaemonSet)
|
||||
*out = *in
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_extensions_RollingUpdateDeployment(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*RollingUpdateDeployment)
|
||||
|
@ -13,6 +13,7 @@ go_library(
|
||||
srcs = [
|
||||
"daemoncontroller.go",
|
||||
"doc.go",
|
||||
"update.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
@ -26,6 +27,7 @@ go_library(
|
||||
"//pkg/client/listers/core/v1:go_default_library",
|
||||
"//pkg/client/listers/extensions/v1beta1:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/daemon/util:go_default_library",
|
||||
"//pkg/util/metrics:go_default_library",
|
||||
"//plugin/pkg/scheduler/algorithm:go_default_library",
|
||||
"//plugin/pkg/scheduler/algorithm/predicates:go_default_library",
|
||||
@ -35,6 +37,7 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
"//vendor:k8s.io/client-go/kubernetes/typed/core/v1",
|
||||
@ -47,7 +50,10 @@ go_library(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["daemoncontroller_test.go"],
|
||||
srcs = [
|
||||
"daemoncontroller_test.go",
|
||||
"update_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
@ -62,6 +68,7 @@ go_test(
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
|
||||
"//vendor:k8s.io/apiserver/pkg/storage/names",
|
||||
"//vendor:k8s.io/client-go/testing",
|
||||
"//vendor:k8s.io/client-go/tools/cache",
|
||||
@ -78,6 +85,9 @@ filegroup(
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/controller/daemon/util:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
@ -44,6 +44,7 @@ import (
|
||||
corelisters "k8s.io/kubernetes/pkg/client/listers/core/v1"
|
||||
extensionslisters "k8s.io/kubernetes/pkg/client/listers/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/controller/daemon/util"
|
||||
"k8s.io/kubernetes/pkg/util/metrics"
|
||||
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
|
||||
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates"
|
||||
@ -255,6 +256,17 @@ func (dsc *DaemonSetsController) enqueueDaemonSet(ds *extensions.DaemonSet) {
|
||||
dsc.queue.Add(key)
|
||||
}
|
||||
|
||||
func (dsc *DaemonSetsController) enqueueDaemonSetAfter(obj interface{}, after time.Duration) {
|
||||
key, err := controller.KeyFunc(obj)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %+v: %v", obj, err))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Handle overlapping controllers better. See comment in ReplicationManager.
|
||||
dsc.queue.AddAfter(key, after)
|
||||
}
|
||||
|
||||
func (dsc *DaemonSetsController) getPodDaemonSet(pod *v1.Pod) *extensions.DaemonSet {
|
||||
// look up in the cache, if cached and the cache is valid, just return cached value
|
||||
if obj, cached := dsc.lookupCache.GetMatchingObject(pod); cached {
|
||||
@ -342,8 +354,14 @@ func (dsc *DaemonSetsController) updatePod(old, cur interface{}) {
|
||||
return
|
||||
}
|
||||
glog.V(4).Infof("Pod %s updated.", curPod.Name)
|
||||
changedToReady := !v1.IsPodReady(oldPod) && v1.IsPodReady(curPod)
|
||||
if curDS := dsc.getPodDaemonSet(curPod); curDS != nil {
|
||||
dsc.enqueueDaemonSet(curDS)
|
||||
|
||||
// See https://github.com/kubernetes/kubernetes/pull/38076 for more details
|
||||
if changedToReady && curDS.Spec.MinReadySeconds > 0 {
|
||||
dsc.enqueueDaemonSetAfter(curDS, time.Duration(curDS.Spec.MinReadySeconds)*time.Second)
|
||||
}
|
||||
}
|
||||
// If the labels have not changed, then the daemon set responsible for
|
||||
// the pod is the same as it was before. In that case we have enqueued the daemon
|
||||
@ -521,11 +539,23 @@ func (dsc *DaemonSetsController) manage(ds *extensions.DaemonSet) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
errors := dsc.syncNodes(ds, podsToDelete, nodesNeedingDaemonPods)
|
||||
|
||||
// Throw an error when the daemon pods fail, to use ratelimiter to prevent kill-recreate hot loop
|
||||
if failedPodsObserved > 0 {
|
||||
errors = append(errors, fmt.Errorf("deleted %d failed pods of DaemonSet %s/%s", failedPodsObserved, ds.Namespace, ds.Name))
|
||||
}
|
||||
|
||||
return utilerrors.NewAggregate(errors)
|
||||
}
|
||||
|
||||
// syncNodes deletes given pods and creates new daemon set pods on the given node
|
||||
// returns slice with erros if any
|
||||
func (dsc *DaemonSetsController) syncNodes(ds *extensions.DaemonSet, podsToDelete, nodesNeedingDaemonPods []string) []error {
|
||||
// We need to set expectations before creating/deleting pods to avoid race conditions.
|
||||
dsKey, err := controller.KeyFunc(ds)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't get key for object %#v: %v", ds, err)
|
||||
return []error{fmt.Errorf("couldn't get key for object %#v: %v", ds, err)}
|
||||
}
|
||||
|
||||
createDiff := len(nodesNeedingDaemonPods)
|
||||
@ -546,10 +576,11 @@ func (dsc *DaemonSetsController) manage(ds *extensions.DaemonSet) error {
|
||||
glog.V(4).Infof("Nodes needing daemon pods for daemon set %s: %+v, creating %d", ds.Name, nodesNeedingDaemonPods, createDiff)
|
||||
createWait := sync.WaitGroup{}
|
||||
createWait.Add(createDiff)
|
||||
template := util.GetPodTemplateWithGeneration(ds.Spec.Template, ds.Spec.TemplateGeneration)
|
||||
for i := 0; i < createDiff; i++ {
|
||||
go func(ix int) {
|
||||
defer createWait.Done()
|
||||
if err := dsc.podControl.CreatePodsOnNode(nodesNeedingDaemonPods[ix], ds.Namespace, &ds.Spec.Template, ds); err != nil {
|
||||
if err := dsc.podControl.CreatePodsOnNode(nodesNeedingDaemonPods[ix], ds.Namespace, &template, ds); err != nil {
|
||||
glog.V(2).Infof("Failed creation, decrementing expectations for set %q/%q", ds.Namespace, ds.Name)
|
||||
dsc.expectations.CreationObserved(dsKey)
|
||||
errCh <- err
|
||||
@ -581,18 +612,17 @@ func (dsc *DaemonSetsController) manage(ds *extensions.DaemonSet) error {
|
||||
for err := range errCh {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
// Throw an error when the daemon pods fail, to use ratelimiter to prevent kill-recreate hot loop
|
||||
if failedPodsObserved > 0 {
|
||||
errors = append(errors, fmt.Errorf("deleted %d failed pods of DaemonSet %s/%s", failedPodsObserved, ds.Namespace, ds.Name))
|
||||
}
|
||||
return utilerrors.NewAggregate(errors)
|
||||
return errors
|
||||
}
|
||||
|
||||
func storeDaemonSetStatus(dsClient unversionedextensions.DaemonSetInterface, ds *extensions.DaemonSet, desiredNumberScheduled, currentNumberScheduled, numberMisscheduled, numberReady int) error {
|
||||
func storeDaemonSetStatus(dsClient unversionedextensions.DaemonSetInterface, ds *extensions.DaemonSet, desiredNumberScheduled, currentNumberScheduled, numberMisscheduled, numberReady, updatedNumberScheduled, numberAvailable, numberUnavailable int) error {
|
||||
if int(ds.Status.DesiredNumberScheduled) == desiredNumberScheduled &&
|
||||
int(ds.Status.CurrentNumberScheduled) == currentNumberScheduled &&
|
||||
int(ds.Status.NumberMisscheduled) == numberMisscheduled &&
|
||||
int(ds.Status.NumberReady) == numberReady &&
|
||||
int(ds.Status.UpdatedNumberScheduled) == updatedNumberScheduled &&
|
||||
int(ds.Status.NumberAvailable) == numberAvailable &&
|
||||
int(ds.Status.NumberUnavailable) == numberUnavailable &&
|
||||
ds.Status.ObservedGeneration >= ds.Generation {
|
||||
return nil
|
||||
}
|
||||
@ -611,6 +641,9 @@ func storeDaemonSetStatus(dsClient unversionedextensions.DaemonSetInterface, ds
|
||||
toUpdate.Status.CurrentNumberScheduled = int32(currentNumberScheduled)
|
||||
toUpdate.Status.NumberMisscheduled = int32(numberMisscheduled)
|
||||
toUpdate.Status.NumberReady = int32(numberReady)
|
||||
toUpdate.Status.UpdatedNumberScheduled = int32(updatedNumberScheduled)
|
||||
toUpdate.Status.NumberAvailable = int32(numberAvailable)
|
||||
toUpdate.Status.NumberUnavailable = int32(numberUnavailable)
|
||||
|
||||
if _, updateErr = dsClient.UpdateStatus(toUpdate); updateErr == nil {
|
||||
return nil
|
||||
@ -638,7 +671,7 @@ func (dsc *DaemonSetsController) updateDaemonSetStatus(ds *extensions.DaemonSet)
|
||||
return fmt.Errorf("couldn't get list of nodes when updating daemon set %#v: %v", ds, err)
|
||||
}
|
||||
|
||||
var desiredNumberScheduled, currentNumberScheduled, numberMisscheduled, numberReady int
|
||||
var desiredNumberScheduled, currentNumberScheduled, numberMisscheduled, numberReady, updatedNumberScheduled, numberAvailable int
|
||||
for i := range nodeList {
|
||||
node := nodeList[i]
|
||||
wantToRun, _, _, err := dsc.nodeShouldRunDaemonPod(node, ds)
|
||||
@ -652,11 +685,18 @@ func (dsc *DaemonSetsController) updateDaemonSetStatus(ds *extensions.DaemonSet)
|
||||
desiredNumberScheduled++
|
||||
if scheduled {
|
||||
currentNumberScheduled++
|
||||
// Sort the daemon pods by creation time, so the the oldest is first.
|
||||
// Sort the daemon pods by creation time, so that the oldest is first.
|
||||
daemonPods, _ := nodeToDaemonPods[node.Name]
|
||||
sort.Sort(podByCreationTimestamp(daemonPods))
|
||||
if v1.IsPodReady(daemonPods[0]) {
|
||||
pod := daemonPods[0]
|
||||
if v1.IsPodReady(pod) {
|
||||
numberReady++
|
||||
if v1.IsPodAvailable(pod, ds.Spec.MinReadySeconds, metav1.Now()) {
|
||||
numberAvailable++
|
||||
}
|
||||
}
|
||||
if util.IsPodUpdated(ds.Spec.TemplateGeneration, pod) {
|
||||
updatedNumberScheduled++
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -665,8 +705,9 @@ func (dsc *DaemonSetsController) updateDaemonSetStatus(ds *extensions.DaemonSet)
|
||||
}
|
||||
}
|
||||
}
|
||||
numberUnavailable := desiredNumberScheduled - numberAvailable
|
||||
|
||||
err = storeDaemonSetStatus(dsc.kubeClient.Extensions().DaemonSets(ds.Namespace), ds, desiredNumberScheduled, currentNumberScheduled, numberMisscheduled, numberReady)
|
||||
err = storeDaemonSetStatus(dsc.kubeClient.Extensions().DaemonSets(ds.Namespace), ds, desiredNumberScheduled, currentNumberScheduled, numberMisscheduled, numberReady, updatedNumberScheduled, numberAvailable, numberUnavailable)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error storing status for daemon set %#v: %v", ds, err)
|
||||
}
|
||||
@ -714,6 +755,17 @@ func (dsc *DaemonSetsController) syncDaemonSet(key string) error {
|
||||
}
|
||||
}
|
||||
|
||||
dsNeedsSync = dsc.expectations.SatisfiedExpectations(dsKey)
|
||||
if dsNeedsSync && ds.DeletionTimestamp == nil {
|
||||
switch ds.Spec.UpdateStrategy.Type {
|
||||
case extensions.RollingUpdateDaemonSetStrategyType:
|
||||
err = dsc.rollingUpdate(ds)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return dsc.updateDaemonSetStatus(ds)
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ package daemon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
@ -166,6 +167,63 @@ func addFailedPods(podStore cache.Store, nodeName string, label map[string]strin
|
||||
}
|
||||
}
|
||||
|
||||
type fakePodControl struct {
|
||||
sync.Mutex
|
||||
*controller.FakePodControl
|
||||
podStore cache.Store
|
||||
podIDMap map[string]*v1.Pod
|
||||
}
|
||||
|
||||
func newFakePodControl() *fakePodControl {
|
||||
podIDMap := make(map[string]*v1.Pod)
|
||||
return &fakePodControl{
|
||||
FakePodControl: &controller.FakePodControl{},
|
||||
podIDMap: podIDMap}
|
||||
}
|
||||
|
||||
func (f *fakePodControl) CreatePodsOnNode(nodeName, namespace string, template *v1.PodTemplateSpec, object runtime.Object) error {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
if err := f.FakePodControl.CreatePodsOnNode(nodeName, namespace, template, object); err != nil {
|
||||
return fmt.Errorf("failed to create pod on node %q", nodeName)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: template.Labels,
|
||||
Namespace: namespace,
|
||||
GenerateName: fmt.Sprintf("%s-", nodeName),
|
||||
},
|
||||
}
|
||||
|
||||
if err := api.Scheme.Convert(&template.Spec, &pod.Spec, nil); err != nil {
|
||||
return fmt.Errorf("unable to convert pod template: %v", err)
|
||||
}
|
||||
if len(nodeName) != 0 {
|
||||
pod.Spec.NodeName = nodeName
|
||||
}
|
||||
pod.Name = names.SimpleNameGenerator.GenerateName(fmt.Sprintf("%s-", nodeName))
|
||||
|
||||
f.podStore.Update(pod)
|
||||
f.podIDMap[pod.Name] = pod
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakePodControl) DeletePod(namespace string, podID string, object runtime.Object) error {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
if err := f.FakePodControl.DeletePod(namespace, podID, object); err != nil {
|
||||
return fmt.Errorf("failed to delete pod %q", podID)
|
||||
}
|
||||
pod, ok := f.podIDMap[podID]
|
||||
if !ok {
|
||||
return fmt.Errorf("pod %q does not exist", podID)
|
||||
}
|
||||
f.podStore.Delete(pod)
|
||||
delete(f.podIDMap, podID)
|
||||
return nil
|
||||
}
|
||||
|
||||
type daemonSetsController struct {
|
||||
*DaemonSetsController
|
||||
|
||||
@ -174,7 +232,7 @@ type daemonSetsController struct {
|
||||
nodeStore cache.Store
|
||||
}
|
||||
|
||||
func newTestController(initialObjects ...runtime.Object) (*daemonSetsController, *controller.FakePodControl, *fake.Clientset) {
|
||||
func newTestController(initialObjects ...runtime.Object) (*daemonSetsController, *fakePodControl, *fake.Clientset) {
|
||||
clientset := fake.NewSimpleClientset(initialObjects...)
|
||||
informerFactory := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc())
|
||||
|
||||
@ -190,8 +248,9 @@ func newTestController(initialObjects ...runtime.Object) (*daemonSetsController,
|
||||
manager.podStoreSynced = alwaysReady
|
||||
manager.nodeStoreSynced = alwaysReady
|
||||
manager.dsStoreSynced = alwaysReady
|
||||
podControl := &controller.FakePodControl{}
|
||||
podControl := newFakePodControl()
|
||||
manager.podControl = podControl
|
||||
podControl.podStore = informerFactory.Core().V1().Pods().Informer().GetStore()
|
||||
|
||||
return &daemonSetsController{
|
||||
manager,
|
||||
@ -201,7 +260,7 @@ func newTestController(initialObjects ...runtime.Object) (*daemonSetsController,
|
||||
}, podControl, clientset
|
||||
}
|
||||
|
||||
func validateSyncDaemonSets(t *testing.T, fakePodControl *controller.FakePodControl, expectedCreates, expectedDeletes int) {
|
||||
func validateSyncDaemonSets(t *testing.T, fakePodControl *fakePodControl, expectedCreates, expectedDeletes int) {
|
||||
if len(fakePodControl.Templates) != expectedCreates {
|
||||
t.Errorf("Unexpected number of creates. Expected %d, saw %d\n", expectedCreates, len(fakePodControl.Templates))
|
||||
}
|
||||
@ -210,7 +269,7 @@ func validateSyncDaemonSets(t *testing.T, fakePodControl *controller.FakePodCont
|
||||
}
|
||||
}
|
||||
|
||||
func syncAndValidateDaemonSets(t *testing.T, manager *daemonSetsController, ds *extensions.DaemonSet, podControl *controller.FakePodControl, expectedCreates, expectedDeletes int) {
|
||||
func syncAndValidateDaemonSets(t *testing.T, manager *daemonSetsController, ds *extensions.DaemonSet, podControl *fakePodControl, expectedCreates, expectedDeletes int) {
|
||||
key, err := controller.KeyFunc(ds)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get key for daemon.")
|
||||
@ -219,6 +278,18 @@ func syncAndValidateDaemonSets(t *testing.T, manager *daemonSetsController, ds *
|
||||
validateSyncDaemonSets(t, podControl, expectedCreates, expectedDeletes)
|
||||
}
|
||||
|
||||
// clearExpectations copies the FakePodControl to PodStore and clears the create and delete expectations.
|
||||
func clearExpectations(t *testing.T, manager *daemonSetsController, ds *extensions.DaemonSet, fakePodControl *fakePodControl) {
|
||||
fakePodControl.Clear()
|
||||
|
||||
key, err := controller.KeyFunc(ds)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get key for daemon.")
|
||||
return
|
||||
}
|
||||
manager.expectations.DeleteExpectations(key)
|
||||
}
|
||||
|
||||
func TestDeleteFinalStateUnknown(t *testing.T) {
|
||||
manager, _, _ := newTestController()
|
||||
addNodes(manager.nodeStore, 0, 1, nil)
|
||||
@ -231,6 +302,15 @@ func TestDeleteFinalStateUnknown(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func markPodsReady(store cache.Store) {
|
||||
// mark pods as ready
|
||||
for _, obj := range store.List() {
|
||||
pod := obj.(*v1.Pod)
|
||||
condition := v1.PodCondition{Type: v1.PodReady, Status: v1.ConditionTrue}
|
||||
v1.UpdatePodCondition(&pod.Status, &condition)
|
||||
}
|
||||
}
|
||||
|
||||
// DaemonSets without node selectors should launch pods on every node.
|
||||
func TestSimpleDaemonSetLaunchesPods(t *testing.T) {
|
||||
manager, podControl, _ := newTestController()
|
||||
|
137
pkg/controller/daemon/update.go
Normal file
137
pkg/controller/daemon/update.go
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
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 daemon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
intstrutil "k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/controller/daemon/util"
|
||||
)
|
||||
|
||||
// rollingUpdate deletes old daemon set pods making sure that no more than
|
||||
// ds.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable pods are unavailable
|
||||
func (dsc *DaemonSetsController) rollingUpdate(ds *extensions.DaemonSet) error {
|
||||
newPods, oldPods, err := dsc.getAllDaemonSetPods(ds)
|
||||
allPods := append(oldPods, newPods...)
|
||||
|
||||
maxUnavailable, numUnavailable, err := dsc.getUnavailableNumbers(ds, allPods)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't get unavailable numbers: %v", err)
|
||||
}
|
||||
oldAvailablePods, oldUnavailablePods := util.SplitByAvailablePods(ds.Spec.MinReadySeconds, oldPods)
|
||||
|
||||
// for oldPods delete all not running pods
|
||||
var podsToDelete []string
|
||||
glog.V(4).Infof("Marking all unavailable old pods for deletion")
|
||||
for _, pod := range oldUnavailablePods {
|
||||
// Skip terminating pods. We won't delete them again
|
||||
if pod.DeletionTimestamp != nil {
|
||||
continue
|
||||
}
|
||||
glog.V(4).Infof("Marking pod %s/%s for deletion", ds.Name, pod.Name)
|
||||
podsToDelete = append(podsToDelete, pod.Name)
|
||||
}
|
||||
|
||||
glog.V(4).Infof("Marking old pods for deletion")
|
||||
for _, pod := range oldAvailablePods {
|
||||
if numUnavailable >= maxUnavailable {
|
||||
glog.V(4).Infof("Number of unavailable DaemonSet pods: %d, is equal to or exceeds allowed maximum: %d", numUnavailable, maxUnavailable)
|
||||
break
|
||||
}
|
||||
glog.V(4).Infof("Marking pod %s/%s for deletion", ds.Name, pod.Name)
|
||||
podsToDelete = append(podsToDelete, pod.Name)
|
||||
numUnavailable++
|
||||
}
|
||||
errors := dsc.syncNodes(ds, podsToDelete, []string{})
|
||||
return utilerrors.NewAggregate(errors)
|
||||
}
|
||||
|
||||
func (dsc *DaemonSetsController) getAllDaemonSetPods(ds *extensions.DaemonSet) ([]*v1.Pod, []*v1.Pod, error) {
|
||||
var newPods []*v1.Pod
|
||||
var oldPods []*v1.Pod
|
||||
|
||||
selector, err := metav1.LabelSelectorAsSelector(ds.Spec.Selector)
|
||||
if err != nil {
|
||||
return newPods, oldPods, err
|
||||
}
|
||||
daemonPods, err := dsc.podLister.Pods(ds.Namespace).List(selector)
|
||||
if err != nil {
|
||||
return newPods, oldPods, fmt.Errorf("Couldn't get list of pods for daemon set %#v: %v", ds, err)
|
||||
}
|
||||
for _, pod := range daemonPods {
|
||||
if util.IsPodUpdated(ds.Spec.TemplateGeneration, pod) {
|
||||
newPods = append(newPods, pod)
|
||||
} else {
|
||||
oldPods = append(oldPods, pod)
|
||||
}
|
||||
}
|
||||
return newPods, oldPods, nil
|
||||
}
|
||||
|
||||
func (dsc *DaemonSetsController) getUnavailableNumbers(ds *extensions.DaemonSet, allPods []*v1.Pod) (int, int, error) {
|
||||
glog.V(4).Infof("Getting unavailable numbers")
|
||||
// TODO: get nodeList once in syncDaemonSet and pass it to other functions
|
||||
nodeList, err := dsc.nodeLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return -1, -1, fmt.Errorf("couldn't get list of nodes during rolling update of daemon set %#v: %v", ds, err)
|
||||
}
|
||||
|
||||
nodeToDaemonPods, err := dsc.getNodesToDaemonPods(ds)
|
||||
if err != nil {
|
||||
return -1, -1, fmt.Errorf("couldn't get node to daemon pods mapping for daemon set %#v: %v", ds, err)
|
||||
}
|
||||
|
||||
var numUnavailable, desiredNumberScheduled int
|
||||
for i := range nodeList {
|
||||
node := nodeList[i]
|
||||
wantToRun, _, _, err := dsc.nodeShouldRunDaemonPod(node, ds)
|
||||
if err != nil {
|
||||
return -1, -1, err
|
||||
}
|
||||
if !wantToRun {
|
||||
continue
|
||||
}
|
||||
desiredNumberScheduled++
|
||||
daemonPods, exists := nodeToDaemonPods[node.Name]
|
||||
if !exists {
|
||||
numUnavailable++
|
||||
continue
|
||||
}
|
||||
available := false
|
||||
for _, pod := range daemonPods {
|
||||
if v1.IsPodAvailable(pod, ds.Spec.MinReadySeconds, metav1.Now()) {
|
||||
available = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !available {
|
||||
numUnavailable++
|
||||
}
|
||||
}
|
||||
maxUnavailable, err := intstrutil.GetValueFromIntOrPercent(ds.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable, desiredNumberScheduled, true)
|
||||
if err != nil {
|
||||
return -1, -1, fmt.Errorf("Invalid value for MaxUnavailable: %v", err)
|
||||
}
|
||||
return maxUnavailable, numUnavailable, nil
|
||||
}
|
135
pkg/controller/daemon/update_test.go
Normal file
135
pkg/controller/daemon/update_test.go
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
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 daemon
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
)
|
||||
|
||||
func TestDaemonSetUpdatesPods(t *testing.T) {
|
||||
manager, podControl, _ := newTestController()
|
||||
maxUnavailable := 2
|
||||
addNodes(manager.nodeStore, 0, 5, nil)
|
||||
ds := newDaemonSet("foo")
|
||||
manager.dsStore.Add(ds)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 5, 0)
|
||||
markPodsReady(podControl.podStore)
|
||||
|
||||
ds.Spec.Template.Spec.Containers[0].Image = "foo2/bar2"
|
||||
ds.Spec.UpdateStrategy.Type = extensions.RollingUpdateDaemonSetStrategyType
|
||||
intStr := intstr.FromInt(maxUnavailable)
|
||||
ds.Spec.UpdateStrategy.RollingUpdate = &extensions.RollingUpdateDaemonSet{MaxUnavailable: &intStr}
|
||||
ds.Spec.TemplateGeneration++
|
||||
manager.dsStore.Update(ds)
|
||||
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 0, maxUnavailable)
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, maxUnavailable, 0)
|
||||
markPodsReady(podControl.podStore)
|
||||
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 0, maxUnavailable)
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, maxUnavailable, 0)
|
||||
markPodsReady(podControl.podStore)
|
||||
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 1)
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 1, 0)
|
||||
markPodsReady(podControl.podStore)
|
||||
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0)
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
}
|
||||
|
||||
func TestDaemonSetUpdatesWhenNewPosIsNotReady(t *testing.T) {
|
||||
manager, podControl, _ := newTestController()
|
||||
maxUnavailable := 3
|
||||
addNodes(manager.nodeStore, 0, 5, nil)
|
||||
ds := newDaemonSet("foo")
|
||||
manager.dsStore.Add(ds)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 5, 0)
|
||||
markPodsReady(podControl.podStore)
|
||||
|
||||
ds.Spec.Template.Spec.Containers[0].Image = "foo2/bar2"
|
||||
ds.Spec.UpdateStrategy.Type = extensions.RollingUpdateDaemonSetStrategyType
|
||||
intStr := intstr.FromInt(maxUnavailable)
|
||||
ds.Spec.UpdateStrategy.RollingUpdate = &extensions.RollingUpdateDaemonSet{MaxUnavailable: &intStr}
|
||||
ds.Spec.TemplateGeneration++
|
||||
manager.dsStore.Update(ds)
|
||||
|
||||
// new pods are not ready numUnavailable == maxUnavailable
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 0, maxUnavailable)
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, maxUnavailable, 0)
|
||||
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0)
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
}
|
||||
|
||||
func TestDaemonSetUpdatesAllOldPodsNotReady(t *testing.T) {
|
||||
manager, podControl, _ := newTestController()
|
||||
maxUnavailable := 3
|
||||
addNodes(manager.nodeStore, 0, 5, nil)
|
||||
ds := newDaemonSet("foo")
|
||||
manager.dsStore.Add(ds)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 5, 0)
|
||||
|
||||
ds.Spec.Template.Spec.Containers[0].Image = "foo2/bar2"
|
||||
ds.Spec.UpdateStrategy.Type = extensions.RollingUpdateDaemonSetStrategyType
|
||||
intStr := intstr.FromInt(maxUnavailable)
|
||||
ds.Spec.UpdateStrategy.RollingUpdate = &extensions.RollingUpdateDaemonSet{MaxUnavailable: &intStr}
|
||||
ds.Spec.TemplateGeneration++
|
||||
manager.dsStore.Update(ds)
|
||||
|
||||
// all old pods are unavailable so should be removed
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 5)
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 5, 0)
|
||||
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0)
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
}
|
||||
|
||||
func TestDaemonSetUpdatesNoTemplateChanged(t *testing.T) {
|
||||
manager, podControl, _ := newTestController()
|
||||
maxUnavailable := 3
|
||||
addNodes(manager.nodeStore, 0, 5, nil)
|
||||
ds := newDaemonSet("foo")
|
||||
manager.dsStore.Add(ds)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 5, 0)
|
||||
|
||||
ds.Spec.UpdateStrategy.Type = extensions.RollingUpdateDaemonSetStrategyType
|
||||
intStr := intstr.FromInt(maxUnavailable)
|
||||
ds.Spec.UpdateStrategy.RollingUpdate = &extensions.RollingUpdateDaemonSet{MaxUnavailable: &intStr}
|
||||
manager.dsStore.Update(ds)
|
||||
|
||||
// template is not changed no pod should be removed
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0)
|
||||
clearExpectations(t, manager, ds, podControl)
|
||||
}
|
48
pkg/controller/daemon/util/BUILD
Normal file
48
pkg/controller/daemon/util/BUILD
Normal file
@ -0,0 +1,48 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["daemonset_util.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/util/labels:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
],
|
||||
)
|
||||
|
||||
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 = ["daemonset_util_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
],
|
||||
)
|
62
pkg/controller/daemon/util/daemonset_util.go
Normal file
62
pkg/controller/daemon/util/daemonset_util.go
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
labelsutil "k8s.io/kubernetes/pkg/util/labels"
|
||||
)
|
||||
|
||||
// GetPodTemplateWithHash returns copy of provided template with additional
|
||||
// label which contains hash of provided template
|
||||
func GetPodTemplateWithGeneration(template v1.PodTemplateSpec, generation int64) v1.PodTemplateSpec {
|
||||
obj, _ := api.Scheme.DeepCopy(template)
|
||||
newTemplate := obj.(v1.PodTemplateSpec)
|
||||
templateGenerationStr := fmt.Sprint(generation)
|
||||
newTemplate.ObjectMeta.Labels = labelsutil.CloneAndAddLabel(
|
||||
template.ObjectMeta.Labels,
|
||||
extensions.DaemonSetTemplateGenerationKey,
|
||||
templateGenerationStr,
|
||||
)
|
||||
return newTemplate
|
||||
}
|
||||
|
||||
// IsPodUpdate checks if pod contains label with provided hash
|
||||
func IsPodUpdated(dsTemplateGeneration int64, pod *v1.Pod) bool {
|
||||
podTemplateGeneration, generationExists := pod.ObjectMeta.Labels[extensions.DaemonSetTemplateGenerationKey]
|
||||
dsTemplateGenerationStr := fmt.Sprint(dsTemplateGeneration)
|
||||
return generationExists && podTemplateGeneration == dsTemplateGenerationStr
|
||||
}
|
||||
|
||||
// SplitByAvailablePods splits provided daemon set pods by availabilty
|
||||
func SplitByAvailablePods(minReadySeconds int32, pods []*v1.Pod) ([]*v1.Pod, []*v1.Pod) {
|
||||
unavailablePods := []*v1.Pod{}
|
||||
availablePods := []*v1.Pod{}
|
||||
for _, pod := range pods {
|
||||
if v1.IsPodAvailable(pod, minReadySeconds, metav1.Now()) {
|
||||
availablePods = append(availablePods, pod)
|
||||
} else {
|
||||
unavailablePods = append(unavailablePods, pod)
|
||||
}
|
||||
}
|
||||
return availablePods, unavailablePods
|
||||
}
|
92
pkg/controller/daemon/util/daemonset_util_test.go
Normal file
92
pkg/controller/daemon/util/daemonset_util_test.go
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
)
|
||||
|
||||
func newPod(podName string, nodeName string, label map[string]string) *v1.Pod {
|
||||
pod := &v1.Pod{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: testapi.Extensions.GroupVersion().String()},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: label,
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
NodeName: nodeName,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: "foo/bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
pod.Name = podName
|
||||
return pod
|
||||
}
|
||||
|
||||
func TestIsPodUpdated(t *testing.T) {
|
||||
tests := []struct {
|
||||
templateGeneration int64
|
||||
pod *v1.Pod
|
||||
isUpdated bool
|
||||
}{
|
||||
{
|
||||
int64(12345),
|
||||
newPod("pod1", "node1", map[string]string{extensions.DaemonSetTemplateGenerationKey: "12345"}),
|
||||
true,
|
||||
},
|
||||
{
|
||||
int64(12355),
|
||||
newPod("pod1", "node1", map[string]string{extensions.DaemonSetTemplateGenerationKey: "12345"}),
|
||||
false,
|
||||
},
|
||||
{
|
||||
int64(12355),
|
||||
newPod("pod1", "node1", map[string]string{}),
|
||||
false,
|
||||
},
|
||||
{
|
||||
int64(12355),
|
||||
newPod("pod1", "node1", nil),
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
updated := IsPodUpdated(test.templateGeneration, test.pod)
|
||||
if updated != test.isUpdated {
|
||||
t.Errorf("IsPodUpdated returned wrong value. Expected %t, got %t. TemplateGeneration: %d", test.isUpdated, updated, test.templateGeneration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPodTemplateWithGeneration(t *testing.T) {
|
||||
generation := int64(1)
|
||||
podTemplateSpec := v1.PodTemplateSpec{}
|
||||
newPodTemplate := GetPodTemplateWithGeneration(podTemplateSpec, generation)
|
||||
label, exists := newPodTemplate.ObjectMeta.Labels[extensions.DaemonSetTemplateGenerationKey]
|
||||
if !exists || label != fmt.Sprint(generation) {
|
||||
t.Errorf("Error in getting podTemplateSpec with label generation. Exists: %t, label: %s", exists, label)
|
||||
}
|
||||
}
|
@ -44,6 +44,8 @@ func GetInternalPodTemplateSpecHash(template api.PodTemplateSpec) uint32 {
|
||||
return podTemplateSpecHasher.Sum32()
|
||||
}
|
||||
|
||||
// TODO: move it to a better place. It's also used by DaemonSets
|
||||
// Maybe to pkg/api/v1/resource_helpers.go
|
||||
func GetPodTemplateSpecHashFnv(template v1.PodTemplateSpec) uint32 {
|
||||
podTemplateSpecHasher := fnv.New32a()
|
||||
hashutil.DeepHashObject(podTemplateSpecHasher, template)
|
||||
|
@ -12826,12 +12826,32 @@ func GetOpenAPIDefinitions(ref openapi.ReferenceCallback) map[string]openapi.Ope
|
||||
Ref: ref("k8s.io/kubernetes/pkg/api/v1.PodTemplateSpec"),
|
||||
},
|
||||
},
|
||||
"updateStrategy": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "UpdateStrategy to replace existing DaemonSet pods with new pods.",
|
||||
Ref: ref("k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DaemonSetUpdateStrategy"),
|
||||
},
|
||||
},
|
||||
"minReadySeconds": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "MinReadySeconds minimum number of seconds for which a newly created DaemonSet pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"templateGeneration": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A sequence number representing a specific generation of the template. Populated by the system. It can be set only during the creation.",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"template"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector", "k8s.io/kubernetes/pkg/api/v1.PodTemplateSpec"},
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector", "k8s.io/kubernetes/pkg/api/v1.PodTemplateSpec", "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DaemonSetUpdateStrategy"},
|
||||
},
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DaemonSetStatus": {
|
||||
Schema: spec.Schema{
|
||||
@ -12873,12 +12893,56 @@ func GetOpenAPIDefinitions(ref openapi.ReferenceCallback) map[string]openapi.Ope
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"updatedNumberScheduled": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "UpdatedNumberScheduled is the total number of nodes that are running updated daemon pod",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"numberAvailable": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "NumberAvailable is the number of nodes that should be running the daemon pod and have one or more of the daemon pod running and available (ready for at least minReadySeconds)",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"numberUnavailable": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "NumberUnavailable is the number of nodes that should be running the daemon pod and have none of the daemon pod running and available (ready for at least minReadySeconds)",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"currentNumberScheduled", "numberMisscheduled", "desiredNumberScheduled", "numberReady"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{},
|
||||
},
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1.DaemonSetUpdateStrategy": {
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"type": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Type of daemon set update. Can be \"RollingUpdate\" or \"OnDelete\". Default is OnDelete.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"rollingUpdate": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Rolling update config params. Present only if DaemonSetUpdateStrategy = RollingUpdate.",
|
||||
Ref: ref("k8s.io/kubernetes/pkg/apis/extensions/v1beta1.RollingUpdateDaemonSet"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1.RollingUpdateDaemonSet"},
|
||||
},
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Deployment": {
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
@ -15031,6 +15095,23 @@ func GetOpenAPIDefinitions(ref openapi.ReferenceCallback) map[string]openapi.Ope
|
||||
},
|
||||
Dependencies: []string{},
|
||||
},
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1.RollingUpdateDaemonSet": {
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Spec to control the desired behavior of daemon set rolling update.",
|
||||
Properties: map[string]spec.Schema{
|
||||
"maxUnavailable": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The maximum number of DaemonSet pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of total number of DaemonSet pods at the start of the update (ex: 10%). Absolute number is calculated from percentage by rounding up. This cannot be 0. Default value is 1. Example: when this is set to 30%, 30% of the currently running DaemonSet pods can be stopped for an update at any given time. The update starts by stopping at most 30% of the currently running DaemonSet pods and then brings up new DaemonSet pods in their place. Once the new pods are ready, it then proceeds onto other DaemonSet pods, thus ensuring that at least 70% of original number of DaemonSet pods are available at all times during the update.",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/util/intstr.IntOrString"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/apimachinery/pkg/util/intstr.IntOrString"},
|
||||
},
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1.RollingUpdateDeployment": {
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
|
@ -36,6 +36,8 @@ func StatusViewerFor(kind schema.GroupKind, c internalclientset.Interface) (Stat
|
||||
switch kind {
|
||||
case extensions.Kind("Deployment"):
|
||||
return &DeploymentStatusViewer{c.Extensions()}, nil
|
||||
case extensions.Kind("DaemonSet"):
|
||||
return &DaemonSetStatusViewer{c.Extensions()}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("no status viewer has been implemented for %v", kind)
|
||||
}
|
||||
@ -44,6 +46,10 @@ type DeploymentStatusViewer struct {
|
||||
c extensionsclient.DeploymentsGetter
|
||||
}
|
||||
|
||||
type DaemonSetStatusViewer struct {
|
||||
c extensionsclient.DaemonSetsGetter
|
||||
}
|
||||
|
||||
// Status returns a message describing deployment status, and a bool value indicating if the status is considered done
|
||||
func (s *DeploymentStatusViewer) Status(namespace, name string, revision int64) (string, bool, error) {
|
||||
deployment, err := s.c.Deployments(namespace).Get(name, metav1.GetOptions{})
|
||||
@ -77,3 +83,23 @@ func (s *DeploymentStatusViewer) Status(namespace, name string, revision int64)
|
||||
}
|
||||
return fmt.Sprintf("Waiting for deployment spec update to be observed...\n"), false, nil
|
||||
}
|
||||
|
||||
// Status returns a message describing daemon set status, and a bool value indicating if the status is considered done
|
||||
func (s *DaemonSetStatusViewer) Status(namespace, name string, revision int64) (string, bool, error) {
|
||||
//ignoring revision as DaemonSets does not have history yet
|
||||
|
||||
daemon, err := s.c.DaemonSets(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
if daemon.Generation <= daemon.Status.ObservedGeneration {
|
||||
if daemon.Status.UpdatedNumberScheduled < daemon.Status.DesiredNumberScheduled {
|
||||
return fmt.Sprintf("Waiting for rollout to finish: %d out of %d new pod have been updated...\n", daemon.Status.UpdatedNumberScheduled, daemon.Status.DesiredNumberScheduled), false, nil
|
||||
}
|
||||
if daemon.Status.NumberAvailable < daemon.Status.DesiredNumberScheduled {
|
||||
return fmt.Sprintf("Waiting for rollout to finish: %d of %d updated pods are available...\n", daemon.Status.NumberAvailable, daemon.Status.DesiredNumberScheduled), false, nil
|
||||
}
|
||||
return fmt.Sprintf("daemon set %q successfully rolled out\n", name), true, nil
|
||||
}
|
||||
return fmt.Sprintf("Waiting for daemon set spec update to be observed...\n"), false, nil
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ func newValidDaemonSet() *extensions.DaemonSet {
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
UpdateStrategy: extensions.DaemonSetUpdateStrategy{
|
||||
Type: extensions.OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}},
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -53,6 +53,9 @@ func (daemonSetStrategy) PrepareForCreate(ctx genericapirequest.Context, obj run
|
||||
daemonSet.Status = extensions.DaemonSetStatus{}
|
||||
|
||||
daemonSet.Generation = 1
|
||||
if daemonSet.Spec.TemplateGeneration < 1 {
|
||||
daemonSet.Spec.TemplateGeneration = 1
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||
@ -63,6 +66,9 @@ func (daemonSetStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, ol
|
||||
// update is not allowed to set status
|
||||
newDaemonSet.Status = oldDaemonSet.Status
|
||||
|
||||
// update is not allowed to set TemplateGeneration
|
||||
newDaemonSet.Spec.TemplateGeneration = oldDaemonSet.Spec.TemplateGeneration
|
||||
|
||||
// Any changes to the spec increment the generation number, any changes to the
|
||||
// status should reflect the generation number of the corresponding object. We push
|
||||
// the burden of managing the status onto the clients because we can't (in general)
|
||||
@ -74,6 +80,11 @@ func (daemonSetStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, ol
|
||||
//
|
||||
// TODO: Any changes to a part of the object that represents desired state (labels,
|
||||
// annotations etc) should also increment the generation.
|
||||
if !reflect.DeepEqual(oldDaemonSet.Spec.Template, newDaemonSet.Spec.Template) {
|
||||
newDaemonSet.Spec.TemplateGeneration = oldDaemonSet.Spec.TemplateGeneration + 1
|
||||
newDaemonSet.Generation = oldDaemonSet.Generation + 1
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(oldDaemonSet.Spec, newDaemonSet.Spec) {
|
||||
newDaemonSet.Generation = oldDaemonSet.Generation + 1
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ var _ = framework.KubeDescribe("Daemon set [Serial]", func() {
|
||||
f = framework.NewDefaultFramework("daemonsets")
|
||||
|
||||
image := "gcr.io/google_containers/serve_hostname:v1.4"
|
||||
redisImage := "gcr.io/google_containers/redis:e2e"
|
||||
dsName := "daemon-set"
|
||||
|
||||
var ns string
|
||||
@ -231,6 +232,64 @@ var _ = framework.KubeDescribe("Daemon set [Serial]", func() {
|
||||
err = wait.Poll(dsRetryPeriod, dsRetryTimeout, checkRunningOnAllNodes(f, label))
|
||||
Expect(err).NotTo(HaveOccurred(), "error waiting for daemon pod to revive")
|
||||
})
|
||||
|
||||
It("Should not update pod when spec was updated and update strategy is on delete", func() {
|
||||
label := map[string]string{daemonsetNameLabel: dsName}
|
||||
|
||||
framework.Logf("Creating simple daemon set %s", dsName)
|
||||
_, err := c.Extensions().DaemonSets(ns).Create(newDaemonSet(dsName, image, label))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Check that daemon pods launch on every node of the cluster.")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = wait.Poll(dsRetryPeriod, dsRetryTimeout, checkRunningOnAllNodes(f, label))
|
||||
Expect(err).NotTo(HaveOccurred(), "error waiting for daemon pod to start")
|
||||
|
||||
By("Update daemon pods image.")
|
||||
ds, err := c.Extensions().DaemonSets(ns).Get(dsName, metav1.GetOptions{})
|
||||
ds.Spec.Template.Spec.Containers[0].Image = redisImage
|
||||
_, err = c.Extensions().DaemonSets(ns).Update(ds)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Check that demon pods have not set updated image.")
|
||||
err = wait.Poll(dsRetryPeriod, dsRetryTimeout, checkDaemonPodsImage(c, ns, label, image))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Check that daemon pods are still running on every node of the cluster.")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = wait.Poll(dsRetryPeriod, dsRetryTimeout, checkRunningOnAllNodes(f, label))
|
||||
Expect(err).NotTo(HaveOccurred(), "error waiting for daemon pod to start")
|
||||
})
|
||||
|
||||
It("Should update pod when spec was updated and update strategy is RollingUpdate", func() {
|
||||
label := map[string]string{daemonsetNameLabel: dsName}
|
||||
|
||||
framework.Logf("Creating simple daemon set %s", dsName)
|
||||
_, err := c.Extensions().DaemonSets(ns).Create(newDaemonSet(dsName, image, label))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Check that daemon pods launch on every node of the cluster.")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = wait.Poll(dsRetryPeriod, dsRetryTimeout, checkRunningOnAllNodes(f, label))
|
||||
Expect(err).NotTo(HaveOccurred(), "error waiting for daemon pod to start")
|
||||
|
||||
By("Update daemon pods image.")
|
||||
ds, err := c.Extensions().DaemonSets(ns).Get(dsName, metav1.GetOptions{})
|
||||
ds.Spec.Template.Spec.Containers[0].Image = redisImage
|
||||
ds.Spec.UpdateStrategy = extensions.DaemonSetUpdateStrategy{Type: extensions.RollingUpdateDaemonSetStrategyType}
|
||||
_, err = c.Extensions().DaemonSets(ns).Update(ds)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Check that demon pods have not set updated image.")
|
||||
err = wait.Poll(dsRetryPeriod, dsRetryTimeout, checkDaemonPodsImage(c, ns, label, redisImage))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Check that daemon pods are still running on every node of the cluster.")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = wait.Poll(dsRetryPeriod, dsRetryTimeout, checkRunningOnAllNodes(f, label))
|
||||
Expect(err).NotTo(HaveOccurred(), "error waiting for daemon pod to start")
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
func newDaemonSet(dsName, image string, label map[string]string) *extensions.DaemonSet {
|
||||
@ -389,3 +448,24 @@ func checkDaemonStatus(f *framework.Framework, dsName string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkDaemonPodsImage(c clientset.Interface, ns string, selector map[string]string, image string) func() (bool, error) {
|
||||
return func() (bool, error) {
|
||||
selector := labels.Set(selector).AsSelector()
|
||||
options := metav1.ListOptions{LabelSelector: selector.String()}
|
||||
podList, err := c.Core().Pods(ns).List(options)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
pods := podList.Items
|
||||
|
||||
for _, pod := range pods {
|
||||
podImage := pod.Spec.Containers[0].Image
|
||||
if podImage != image || !v1.IsPodReady(&pod) {
|
||||
framework.Logf("Wrong image for pod: %s. Expected: %s, got: %s. Pod Ready: %t", pod.Name, image, podImage, v1.IsPodReady(&pod))
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user