Commit 26d7ee04 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #44774 from kargakis/uniquifier

Automatic merge from submit-queue Switch Deployments to new hashing algo w/ collision avoidance mechanism Implements https://github.com/kubernetes/community/pull/477 @kubernetes/sig-apps-api-reviews @kubernetes/sig-apps-pr-reviews Fixes https://github.com/kubernetes/kubernetes/issues/29735 Fixes https://github.com/kubernetes/kubernetes/issues/43948 ```release-note Deployments are updated to use (1) a more stable hashing algorithm (fnv) than the previous one (adler) and (2) a hashing collision avoidance mechanism that will ensure new rollouts will not block on hashing collisions anymore. ```
parents 9c1480bb 9190a47c
...@@ -47259,6 +47259,11 @@ ...@@ -47259,6 +47259,11 @@
"type": "integer", "type": "integer",
"format": "int32" "format": "int32"
}, },
"collisionCount": {
"description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.",
"type": "integer",
"format": "int64"
},
"conditions": { "conditions": {
"description": "Represents the latest available observations of a deployment's current state.", "description": "Represents the latest available observations of a deployment's current state.",
"type": "array", "type": "array",
...@@ -49477,6 +49482,11 @@ ...@@ -49477,6 +49482,11 @@
"type": "integer", "type": "integer",
"format": "int32" "format": "int32"
}, },
"collisionCount": {
"description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.",
"type": "integer",
"format": "int64"
},
"conditions": { "conditions": {
"description": "Represents the latest available observations of a deployment's current state.", "description": "Represents the latest available observations of a deployment's current state.",
"type": "array", "type": "array",
...@@ -4706,6 +4706,11 @@ ...@@ -4706,6 +4706,11 @@
"$ref": "v1beta1.DeploymentCondition" "$ref": "v1beta1.DeploymentCondition"
}, },
"description": "Represents the latest available observations of a deployment's current state." "description": "Represents the latest available observations of a deployment's current state."
},
"collisionCount": {
"type": "integer",
"format": "int64",
"description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet."
} }
} }
}, },
......
...@@ -9408,6 +9408,11 @@ ...@@ -9408,6 +9408,11 @@
"$ref": "v1beta1.DeploymentCondition" "$ref": "v1beta1.DeploymentCondition"
}, },
"description": "Represents the latest available observations of a deployment's current state." "description": "Represents the latest available observations of a deployment's current state."
},
"collisionCount": {
"type": "integer",
"format": "int64",
"description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet."
} }
} }
}, },
......
...@@ -466,6 +466,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; } ...@@ -466,6 +466,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_deploymentcondition">v1beta1.DeploymentCondition</a> array</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_deploymentcondition">v1beta1.DeploymentCondition</a> array</p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>
</tr> </tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">collisionCount</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.</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> </tbody>
</table> </table>
...@@ -6470,7 +6477,7 @@ Examples:<br> ...@@ -6470,7 +6477,7 @@ Examples:<br>
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2017-05-22 06:32:54 UTC Last updated 2017-05-25 09:31:33 UTC
</div> </div>
</div> </div>
</body> </body>
......
...@@ -496,6 +496,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; } ...@@ -496,6 +496,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_deploymentcondition">v1beta1.DeploymentCondition</a> array</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_deploymentcondition">v1beta1.DeploymentCondition</a> array</p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>
</tr> </tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">collisionCount</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.</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> </tbody>
</table> </table>
...@@ -8110,7 +8117,7 @@ Both these may change in the future. Incoming requests are matched against the h ...@@ -8110,7 +8117,7 @@ Both these may change in the future. Incoming requests are matched against the h
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2017-05-22 06:33:43 UTC Last updated 2017-05-25 09:32:15 UTC
</div> </div>
</div> </div>
</body> </body>
......
...@@ -13315,6 +13315,11 @@ ...@@ -13315,6 +13315,11 @@
"type": "integer", "type": "integer",
"format": "int32" "format": "int32"
}, },
"collisionCount": {
"description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.",
"type": "integer",
"format": "int64"
},
"conditions": { "conditions": {
"description": "Represents the latest available observations of a deployment's current state.", "description": "Represents the latest available observations of a deployment's current state.",
"type": "array", "type": "array",
......
...@@ -7152,6 +7152,11 @@ ...@@ -7152,6 +7152,11 @@
"$ref": "v1beta1.DeploymentCondition" "$ref": "v1beta1.DeploymentCondition"
}, },
"description": "Represents the latest available observations of a deployment's current state." "description": "Represents the latest available observations of a deployment's current state."
},
"collisionCount": {
"type": "integer",
"format": "int64",
"description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet."
} }
} }
}, },
......
...@@ -478,6 +478,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; } ...@@ -478,6 +478,13 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_deploymentcondition">v1beta1.DeploymentCondition</a> array</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_deploymentcondition">v1beta1.DeploymentCondition</a> array</p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>
</tr> </tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">collisionCount</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.</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> </tbody>
</table> </table>
...@@ -7190,7 +7197,7 @@ Both these may change in the future. Incoming requests are matched against the h ...@@ -7190,7 +7197,7 @@ Both these may change in the future. Incoming requests are matched against the h
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2017-05-22 07:30:41 UTC Last updated 2017-05-25 09:37:16 UTC
</div> </div>
</div> </div>
</body> </body>
......
...@@ -170,6 +170,12 @@ message DeploymentStatus { ...@@ -170,6 +170,12 @@ message DeploymentStatus {
// +patchMergeKey=type // +patchMergeKey=type
// +patchStrategy=merge // +patchStrategy=merge
repeated DeploymentCondition conditions = 6; repeated DeploymentCondition conditions = 6;
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
optional int64 collisionCount = 8;
} }
// DeploymentStrategy describes how to replace existing pods with new ones. // DeploymentStrategy describes how to replace existing pods with new ones.
......
...@@ -4672,7 +4672,7 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -4672,7 +4672,7 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} else { } else {
yysep2 := !z.EncBinary() yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [7]bool var yyq2 [8]bool
_, _, _ = yysep2, yyq2, yy2arr2 _, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false const yyr2 bool = false
yyq2[0] = x.ObservedGeneration != 0 yyq2[0] = x.ObservedGeneration != 0
...@@ -4682,9 +4682,10 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -4682,9 +4682,10 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
yyq2[4] = x.AvailableReplicas != 0 yyq2[4] = x.AvailableReplicas != 0
yyq2[5] = x.UnavailableReplicas != 0 yyq2[5] = x.UnavailableReplicas != 0
yyq2[6] = len(x.Conditions) != 0 yyq2[6] = len(x.Conditions) != 0
yyq2[7] = x.CollisionCount != nil
var yynn2 int var yynn2 int
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
r.EncodeArrayStart(7) r.EncodeArrayStart(8)
} else { } else {
yynn2 = 0 yynn2 = 0
for _, b := range yyq2 { for _, b := range yyq2 {
...@@ -4879,6 +4880,41 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -4879,6 +4880,41 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} }
} }
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[7] {
if x.CollisionCount == nil {
r.EncodeNil()
} else {
yy25 := *x.CollisionCount
yym26 := z.EncBinary()
_ = yym26
if false {
} else {
r.EncodeInt(int64(yy25))
}
}
} else {
r.EncodeNil()
}
} else {
if yyq2[7] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("collisionCount"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
if x.CollisionCount == nil {
r.EncodeNil()
} else {
yy27 := *x.CollisionCount
yym28 := z.EncBinary()
_ = yym28
if false {
} else {
r.EncodeInt(int64(yy27))
}
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234) z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else { } else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234) z.EncSendContainerState(codecSelfer_containerMapEnd1234)
...@@ -5023,6 +5059,22 @@ func (x *DeploymentStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { ...@@ -5023,6 +5059,22 @@ func (x *DeploymentStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv16), d) h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv16), d)
} }
} }
case "collisionCount":
if r.TryDecodeAsNil() {
if x.CollisionCount != nil {
x.CollisionCount = nil
}
} else {
if x.CollisionCount == nil {
x.CollisionCount = new(int64)
}
yym19 := z.DecBinary()
_ = yym19
if false {
} else {
*((*int64)(x.CollisionCount)) = int64(r.DecodeInt(64))
}
}
default: default:
z.DecStructFieldNotFound(-1, yys3) z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3 } // end switch yys3
...@@ -5034,16 +5086,16 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5034,16 +5086,16 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
var yyj18 int var yyj20 int
var yyb18 bool var yyb20 bool
var yyhl18 bool = l >= 0 var yyhl20 bool = l >= 0
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5051,21 +5103,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5051,21 +5103,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ObservedGeneration = 0 x.ObservedGeneration = 0
} else { } else {
yyv19 := &x.ObservedGeneration yyv21 := &x.ObservedGeneration
yym20 := z.DecBinary() yym22 := z.DecBinary()
_ = yym20 _ = yym22
if false { if false {
} else { } else {
*((*int64)(yyv19)) = int64(r.DecodeInt(64)) *((*int64)(yyv21)) = int64(r.DecodeInt(64))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5073,21 +5125,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5073,21 +5125,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Replicas = 0 x.Replicas = 0
} else { } else {
yyv21 := &x.Replicas yyv23 := &x.Replicas
yym22 := z.DecBinary() yym24 := z.DecBinary()
_ = yym22 _ = yym24
if false { if false {
} else { } else {
*((*int32)(yyv21)) = int32(r.DecodeInt(32)) *((*int32)(yyv23)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5095,21 +5147,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5095,21 +5147,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.UpdatedReplicas = 0 x.UpdatedReplicas = 0
} else { } else {
yyv23 := &x.UpdatedReplicas yyv25 := &x.UpdatedReplicas
yym24 := z.DecBinary() yym26 := z.DecBinary()
_ = yym24 _ = yym26
if false { if false {
} else { } else {
*((*int32)(yyv23)) = int32(r.DecodeInt(32)) *((*int32)(yyv25)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5117,21 +5169,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5117,21 +5169,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ReadyReplicas = 0 x.ReadyReplicas = 0
} else { } else {
yyv25 := &x.ReadyReplicas yyv27 := &x.ReadyReplicas
yym26 := z.DecBinary() yym28 := z.DecBinary()
_ = yym26 _ = yym28
if false { if false {
} else { } else {
*((*int32)(yyv25)) = int32(r.DecodeInt(32)) *((*int32)(yyv27)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5139,21 +5191,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5139,21 +5191,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.AvailableReplicas = 0 x.AvailableReplicas = 0
} else { } else {
yyv27 := &x.AvailableReplicas yyv29 := &x.AvailableReplicas
yym28 := z.DecBinary() yym30 := z.DecBinary()
_ = yym28 _ = yym30
if false { if false {
} else { } else {
*((*int32)(yyv27)) = int32(r.DecodeInt(32)) *((*int32)(yyv29)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5161,21 +5213,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5161,21 +5213,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.UnavailableReplicas = 0 x.UnavailableReplicas = 0
} else { } else {
yyv29 := &x.UnavailableReplicas yyv31 := &x.UnavailableReplicas
yym30 := z.DecBinary() yym32 := z.DecBinary()
_ = yym30 _ = yym32
if false { if false {
} else { } else {
*((*int32)(yyv29)) = int32(r.DecodeInt(32)) *((*int32)(yyv31)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5183,26 +5235,52 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5183,26 +5235,52 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Conditions = nil x.Conditions = nil
} else { } else {
yyv31 := &x.Conditions yyv33 := &x.Conditions
yym32 := z.DecBinary() yym34 := z.DecBinary()
_ = yym32 _ = yym34
if false {
} else {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv33), d)
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
if x.CollisionCount != nil {
x.CollisionCount = nil
}
} else {
if x.CollisionCount == nil {
x.CollisionCount = new(int64)
}
yym36 := z.DecBinary()
_ = yym36
if false { if false {
} else { } else {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv31), d) *((*int64)(x.CollisionCount)) = int64(r.DecodeInt(64))
} }
} }
for { for {
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
break break
} }
z.DecSendContainerState(codecSelfer_containerArrayElem1234) z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj18-1, "") z.DecStructFieldNotFound(yyj20-1, "")
} }
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} }
...@@ -6470,7 +6548,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode ...@@ -6470,7 +6548,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode
yyrg1 := len(yyv1) > 0 yyrg1 := len(yyv1) > 0
yyv21 := yyv1 yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 960) yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 968)
if yyrt1 { if yyrt1 {
if yyrl1 <= cap(yyv1) { if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1] yyv1 = yyv1[:yyrl1]
......
...@@ -356,6 +356,12 @@ type DeploymentStatus struct { ...@@ -356,6 +356,12 @@ type DeploymentStatus struct {
// +patchMergeKey=type // +patchMergeKey=type
// +patchStrategy=merge // +patchStrategy=merge
Conditions []DeploymentCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,6,rep,name=conditions"` Conditions []DeploymentCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,6,rep,name=conditions"`
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
CollisionCount *int64 `json:"collisionCount,omitempty" protobuf:"varint,8,opt,name=collisionCount"`
} }
type DeploymentConditionType string type DeploymentConditionType string
......
...@@ -99,6 +99,7 @@ var map_DeploymentStatus = map[string]string{ ...@@ -99,6 +99,7 @@ var map_DeploymentStatus = map[string]string{
"availableReplicas": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.", "availableReplicas": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.",
"unavailableReplicas": "Total number of unavailable pods targeted by this deployment.", "unavailableReplicas": "Total number of unavailable pods targeted by this deployment.",
"conditions": "Represents the latest available observations of a deployment's current state.", "conditions": "Represents the latest available observations of a deployment's current state.",
"collisionCount": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.",
} }
func (DeploymentStatus) SwaggerDoc() map[string]string { func (DeploymentStatus) SwaggerDoc() map[string]string {
......
...@@ -184,6 +184,11 @@ func DeepCopy_v1beta1_DeploymentStatus(in interface{}, out interface{}, c *conve ...@@ -184,6 +184,11 @@ func DeepCopy_v1beta1_DeploymentStatus(in interface{}, out interface{}, c *conve
} }
} }
} }
if in.CollisionCount != nil {
in, out := &in.CollisionCount, &out.CollisionCount
*out = new(int64)
**out = **in
}
return nil return nil
} }
} }
......
...@@ -327,6 +327,12 @@ type DeploymentStatus struct { ...@@ -327,6 +327,12 @@ type DeploymentStatus struct {
// Represents the latest available observations of a deployment's current state. // Represents the latest available observations of a deployment's current state.
Conditions []DeploymentCondition Conditions []DeploymentCondition
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
CollisionCount *int64
} }
type DeploymentConditionType string type DeploymentConditionType string
......
...@@ -325,6 +325,12 @@ message DeploymentStatus { ...@@ -325,6 +325,12 @@ message DeploymentStatus {
// +patchMergeKey=type // +patchMergeKey=type
// +patchStrategy=merge // +patchStrategy=merge
repeated DeploymentCondition conditions = 6; repeated DeploymentCondition conditions = 6;
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
optional int64 collisionCount = 8;
} }
// DeploymentStrategy describes how to replace existing pods with new ones. // DeploymentStrategy describes how to replace existing pods with new ones.
......
...@@ -5606,7 +5606,7 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -5606,7 +5606,7 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} else { } else {
yysep2 := !z.EncBinary() yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [7]bool var yyq2 [8]bool
_, _, _ = yysep2, yyq2, yy2arr2 _, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false const yyr2 bool = false
yyq2[0] = x.ObservedGeneration != 0 yyq2[0] = x.ObservedGeneration != 0
...@@ -5616,9 +5616,10 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -5616,9 +5616,10 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
yyq2[4] = x.AvailableReplicas != 0 yyq2[4] = x.AvailableReplicas != 0
yyq2[5] = x.UnavailableReplicas != 0 yyq2[5] = x.UnavailableReplicas != 0
yyq2[6] = len(x.Conditions) != 0 yyq2[6] = len(x.Conditions) != 0
yyq2[7] = x.CollisionCount != nil
var yynn2 int var yynn2 int
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
r.EncodeArrayStart(7) r.EncodeArrayStart(8)
} else { } else {
yynn2 = 0 yynn2 = 0
for _, b := range yyq2 { for _, b := range yyq2 {
...@@ -5813,6 +5814,41 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -5813,6 +5814,41 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} }
} }
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[7] {
if x.CollisionCount == nil {
r.EncodeNil()
} else {
yy25 := *x.CollisionCount
yym26 := z.EncBinary()
_ = yym26
if false {
} else {
r.EncodeInt(int64(yy25))
}
}
} else {
r.EncodeNil()
}
} else {
if yyq2[7] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("collisionCount"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
if x.CollisionCount == nil {
r.EncodeNil()
} else {
yy27 := *x.CollisionCount
yym28 := z.EncBinary()
_ = yym28
if false {
} else {
r.EncodeInt(int64(yy27))
}
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234) z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else { } else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234) z.EncSendContainerState(codecSelfer_containerMapEnd1234)
...@@ -5957,6 +5993,22 @@ func (x *DeploymentStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { ...@@ -5957,6 +5993,22 @@ func (x *DeploymentStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv16), d) h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv16), d)
} }
} }
case "collisionCount":
if r.TryDecodeAsNil() {
if x.CollisionCount != nil {
x.CollisionCount = nil
}
} else {
if x.CollisionCount == nil {
x.CollisionCount = new(int64)
}
yym19 := z.DecBinary()
_ = yym19
if false {
} else {
*((*int64)(x.CollisionCount)) = int64(r.DecodeInt(64))
}
}
default: default:
z.DecStructFieldNotFound(-1, yys3) z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3 } // end switch yys3
...@@ -5968,16 +6020,16 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5968,16 +6020,16 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
var yyj18 int var yyj20 int
var yyb18 bool var yyb20 bool
var yyhl18 bool = l >= 0 var yyhl20 bool = l >= 0
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5985,21 +6037,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5985,21 +6037,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ObservedGeneration = 0 x.ObservedGeneration = 0
} else { } else {
yyv19 := &x.ObservedGeneration yyv21 := &x.ObservedGeneration
yym20 := z.DecBinary() yym22 := z.DecBinary()
_ = yym20 _ = yym22
if false { if false {
} else { } else {
*((*int64)(yyv19)) = int64(r.DecodeInt(64)) *((*int64)(yyv21)) = int64(r.DecodeInt(64))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6007,21 +6059,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6007,21 +6059,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Replicas = 0 x.Replicas = 0
} else { } else {
yyv21 := &x.Replicas yyv23 := &x.Replicas
yym22 := z.DecBinary() yym24 := z.DecBinary()
_ = yym22 _ = yym24
if false { if false {
} else { } else {
*((*int32)(yyv21)) = int32(r.DecodeInt(32)) *((*int32)(yyv23)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6029,21 +6081,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6029,21 +6081,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.UpdatedReplicas = 0 x.UpdatedReplicas = 0
} else { } else {
yyv23 := &x.UpdatedReplicas yyv25 := &x.UpdatedReplicas
yym24 := z.DecBinary() yym26 := z.DecBinary()
_ = yym24 _ = yym26
if false { if false {
} else { } else {
*((*int32)(yyv23)) = int32(r.DecodeInt(32)) *((*int32)(yyv25)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6051,21 +6103,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6051,21 +6103,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ReadyReplicas = 0 x.ReadyReplicas = 0
} else { } else {
yyv25 := &x.ReadyReplicas yyv27 := &x.ReadyReplicas
yym26 := z.DecBinary() yym28 := z.DecBinary()
_ = yym26 _ = yym28
if false { if false {
} else { } else {
*((*int32)(yyv25)) = int32(r.DecodeInt(32)) *((*int32)(yyv27)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6073,21 +6125,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6073,21 +6125,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.AvailableReplicas = 0 x.AvailableReplicas = 0
} else { } else {
yyv27 := &x.AvailableReplicas yyv29 := &x.AvailableReplicas
yym28 := z.DecBinary() yym30 := z.DecBinary()
_ = yym28 _ = yym30
if false { if false {
} else { } else {
*((*int32)(yyv27)) = int32(r.DecodeInt(32)) *((*int32)(yyv29)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6095,21 +6147,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6095,21 +6147,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.UnavailableReplicas = 0 x.UnavailableReplicas = 0
} else { } else {
yyv29 := &x.UnavailableReplicas yyv31 := &x.UnavailableReplicas
yym30 := z.DecBinary() yym32 := z.DecBinary()
_ = yym30 _ = yym32
if false { if false {
} else { } else {
*((*int32)(yyv29)) = int32(r.DecodeInt(32)) *((*int32)(yyv31)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6117,26 +6169,52 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6117,26 +6169,52 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Conditions = nil x.Conditions = nil
} else { } else {
yyv31 := &x.Conditions yyv33 := &x.Conditions
yym32 := z.DecBinary() yym34 := z.DecBinary()
_ = yym32 _ = yym34
if false {
} else {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv33), d)
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
if x.CollisionCount != nil {
x.CollisionCount = nil
}
} else {
if x.CollisionCount == nil {
x.CollisionCount = new(int64)
}
yym36 := z.DecBinary()
_ = yym36
if false { if false {
} else { } else {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv31), d) *((*int64)(x.CollisionCount)) = int64(r.DecodeInt(64))
} }
} }
for { for {
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
break break
} }
z.DecSendContainerState(codecSelfer_containerArrayElem1234) z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj18-1, "") z.DecStructFieldNotFound(yyj20-1, "")
} }
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} }
...@@ -19652,7 +19730,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode ...@@ -19652,7 +19730,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode
yyrg1 := len(yyv1) > 0 yyrg1 := len(yyv1) > 0
yyv21 := yyv1 yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 960) yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 968)
if yyrt1 { if yyrt1 {
if yyrl1 <= cap(yyv1) { if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1] yyv1 = yyv1[:yyrl1]
......
...@@ -325,6 +325,12 @@ type DeploymentStatus struct { ...@@ -325,6 +325,12 @@ type DeploymentStatus struct {
// +patchMergeKey=type // +patchMergeKey=type
// +patchStrategy=merge // +patchStrategy=merge
Conditions []DeploymentCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,6,rep,name=conditions"` Conditions []DeploymentCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,6,rep,name=conditions"`
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
CollisionCount *int64 `json:"collisionCount,omitempty" protobuf:"varint,8,opt,name=collisionCount"`
} }
type DeploymentConditionType string type DeploymentConditionType string
......
...@@ -186,6 +186,7 @@ var map_DeploymentStatus = map[string]string{ ...@@ -186,6 +186,7 @@ var map_DeploymentStatus = map[string]string{
"availableReplicas": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.", "availableReplicas": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.",
"unavailableReplicas": "Total number of unavailable pods targeted by this deployment.", "unavailableReplicas": "Total number of unavailable pods targeted by this deployment.",
"conditions": "Represents the latest available observations of a deployment's current state.", "conditions": "Represents the latest available observations of a deployment's current state.",
"collisionCount": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.",
} }
func (DeploymentStatus) SwaggerDoc() map[string]string { func (DeploymentStatus) SwaggerDoc() map[string]string {
......
...@@ -628,6 +628,7 @@ func autoConvert_v1beta1_DeploymentStatus_To_extensions_DeploymentStatus(in *Dep ...@@ -628,6 +628,7 @@ func autoConvert_v1beta1_DeploymentStatus_To_extensions_DeploymentStatus(in *Dep
out.AvailableReplicas = in.AvailableReplicas out.AvailableReplicas = in.AvailableReplicas
out.UnavailableReplicas = in.UnavailableReplicas out.UnavailableReplicas = in.UnavailableReplicas
out.Conditions = *(*[]extensions.DeploymentCondition)(unsafe.Pointer(&in.Conditions)) out.Conditions = *(*[]extensions.DeploymentCondition)(unsafe.Pointer(&in.Conditions))
out.CollisionCount = (*int64)(unsafe.Pointer(in.CollisionCount))
return nil return nil
} }
...@@ -644,6 +645,7 @@ func autoConvert_extensions_DeploymentStatus_To_v1beta1_DeploymentStatus(in *ext ...@@ -644,6 +645,7 @@ func autoConvert_extensions_DeploymentStatus_To_v1beta1_DeploymentStatus(in *ext
out.AvailableReplicas = in.AvailableReplicas out.AvailableReplicas = in.AvailableReplicas
out.UnavailableReplicas = in.UnavailableReplicas out.UnavailableReplicas = in.UnavailableReplicas
out.Conditions = *(*[]DeploymentCondition)(unsafe.Pointer(&in.Conditions)) out.Conditions = *(*[]DeploymentCondition)(unsafe.Pointer(&in.Conditions))
out.CollisionCount = (*int64)(unsafe.Pointer(in.CollisionCount))
return nil return nil
} }
......
...@@ -384,6 +384,11 @@ func DeepCopy_v1beta1_DeploymentStatus(in interface{}, out interface{}, c *conve ...@@ -384,6 +384,11 @@ func DeepCopy_v1beta1_DeploymentStatus(in interface{}, out interface{}, c *conve
} }
} }
} }
if in.CollisionCount != nil {
in, out := &in.CollisionCount, &out.CollisionCount
*out = new(int64)
**out = **in
}
return nil return nil
} }
} }
......
...@@ -41,6 +41,7 @@ go_test( ...@@ -41,6 +41,7 @@ go_test(
"//pkg/security/apparmor:go_default_library", "//pkg/security/apparmor:go_default_library",
"//pkg/security/podsecuritypolicy/seccomp:go_default_library", "//pkg/security/podsecuritypolicy/seccomp:go_default_library",
"//pkg/security/podsecuritypolicy/util:go_default_library", "//pkg/security/podsecuritypolicy/util:go_default_library",
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
......
...@@ -346,6 +346,9 @@ func ValidateDeploymentStatus(status *extensions.DeploymentStatus, fldPath *fiel ...@@ -346,6 +346,9 @@ func ValidateDeploymentStatus(status *extensions.DeploymentStatus, fldPath *fiel
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.ReadyReplicas), fldPath.Child("readyReplicas"))...) allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.ReadyReplicas), fldPath.Child("readyReplicas"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.AvailableReplicas), fldPath.Child("availableReplicas"))...) allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.AvailableReplicas), fldPath.Child("availableReplicas"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.UnavailableReplicas), fldPath.Child("unavailableReplicas"))...) allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.UnavailableReplicas), fldPath.Child("unavailableReplicas"))...)
if status.CollisionCount != nil {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(*status.CollisionCount, fldPath.Child("collisionCount"))...)
}
msg := "cannot be greater than status.replicas" msg := "cannot be greater than status.replicas"
if status.UpdatedReplicas > status.Replicas { if status.UpdatedReplicas > status.Replicas {
allErrs = append(allErrs, field.Invalid(fldPath.Child("updatedReplicas"), status.UpdatedReplicas, msg)) allErrs = append(allErrs, field.Invalid(fldPath.Child("updatedReplicas"), status.UpdatedReplicas, msg))
...@@ -372,10 +375,29 @@ func ValidateDeploymentUpdate(update, old *extensions.Deployment) field.ErrorLis ...@@ -372,10 +375,29 @@ func ValidateDeploymentUpdate(update, old *extensions.Deployment) field.ErrorLis
func ValidateDeploymentStatusUpdate(update, old *extensions.Deployment) field.ErrorList { func ValidateDeploymentStatusUpdate(update, old *extensions.Deployment) field.ErrorList {
allErrs := apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata")) allErrs := apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateDeploymentStatus(&update.Status, field.NewPath("status"))...) fldPath := field.NewPath("status")
allErrs = append(allErrs, ValidateDeploymentStatus(&update.Status, fldPath)...)
if isDecremented(update.Status.CollisionCount, old.Status.CollisionCount) {
value := int64(0)
if update.Status.CollisionCount != nil {
value = *update.Status.CollisionCount
}
allErrs = append(allErrs, field.Invalid(fldPath.Child("collisionCount"), value, "cannot be decremented"))
}
return allErrs return allErrs
} }
// TODO: Move in "k8s.io/kubernetes/pkg/api/validation"
func isDecremented(update, old *int64) bool {
if update == nil && old != nil {
return true
}
if update == nil || old == nil {
return false
}
return *update < *old
}
func ValidateDeployment(obj *extensions.Deployment) field.ErrorList { func ValidateDeployment(obj *extensions.Deployment) field.ErrorList {
allErrs := apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateDeploymentName, field.NewPath("metadata")) allErrs := apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateDeploymentName, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateDeploymentSpec(&obj.Spec, field.NewPath("spec"))...) allErrs = append(allErrs, ValidateDeploymentSpec(&obj.Spec, field.NewPath("spec"))...)
......
...@@ -21,6 +21,8 @@ import ( ...@@ -21,6 +21,8 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/davecgh/go-spew/spew"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
...@@ -1230,6 +1232,11 @@ func TestValidateDeployment(t *testing.T) { ...@@ -1230,6 +1232,11 @@ func TestValidateDeployment(t *testing.T) {
} }
} }
func int64p(i int) *int64 {
i64 := int64(i)
return &i64
}
func TestValidateDeploymentStatus(t *testing.T) { func TestValidateDeploymentStatus(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
...@@ -1239,6 +1246,7 @@ func TestValidateDeploymentStatus(t *testing.T) { ...@@ -1239,6 +1246,7 @@ func TestValidateDeploymentStatus(t *testing.T) {
readyReplicas int32 readyReplicas int32
availableReplicas int32 availableReplicas int32
observedGeneration int64 observedGeneration int64
collisionCount *int64
expectedErr bool expectedErr bool
}{ }{
...@@ -1335,6 +1343,13 @@ func TestValidateDeploymentStatus(t *testing.T) { ...@@ -1335,6 +1343,13 @@ func TestValidateDeploymentStatus(t *testing.T) {
observedGeneration: 1, observedGeneration: 1,
expectedErr: false, expectedErr: false,
}, },
{
name: "invalid collisionCount",
replicas: 3,
observedGeneration: 1,
collisionCount: int64p(-3),
expectedErr: true,
},
} }
for _, test := range tests { for _, test := range tests {
...@@ -1344,10 +1359,82 @@ func TestValidateDeploymentStatus(t *testing.T) { ...@@ -1344,10 +1359,82 @@ func TestValidateDeploymentStatus(t *testing.T) {
ReadyReplicas: test.readyReplicas, ReadyReplicas: test.readyReplicas,
AvailableReplicas: test.availableReplicas, AvailableReplicas: test.availableReplicas,
ObservedGeneration: test.observedGeneration, ObservedGeneration: test.observedGeneration,
CollisionCount: test.collisionCount,
} }
if hasErr := len(ValidateDeploymentStatus(&status, field.NewPath("status"))) > 0; hasErr != test.expectedErr { errs := ValidateDeploymentStatus(&status, field.NewPath("status"))
t.Errorf("%s: expected error: %t, got error: %t", test.name, test.expectedErr, hasErr) if hasErr := len(errs) > 0; hasErr != test.expectedErr {
errString := spew.Sprintf("%#v", errs)
t.Errorf("%s: expected error: %t, got error: %t\nerrors: %s", test.name, test.expectedErr, hasErr, errString)
}
}
}
func TestValidateDeploymentStatusUpdate(t *testing.T) {
tests := []struct {
name string
from, to extensions.DeploymentStatus
expectedErr bool
}{
{
name: "increase: valid update",
from: extensions.DeploymentStatus{
CollisionCount: nil,
},
to: extensions.DeploymentStatus{
CollisionCount: int64p(1),
},
expectedErr: false,
},
{
name: "stable: valid update",
from: extensions.DeploymentStatus{
CollisionCount: int64p(1),
},
to: extensions.DeploymentStatus{
CollisionCount: int64p(1),
},
expectedErr: false,
},
{
name: "unset: invalid update",
from: extensions.DeploymentStatus{
CollisionCount: int64p(1),
},
to: extensions.DeploymentStatus{
CollisionCount: nil,
},
expectedErr: true,
},
{
name: "decrease: invalid update",
from: extensions.DeploymentStatus{
CollisionCount: int64p(2),
},
to: extensions.DeploymentStatus{
CollisionCount: int64p(1),
},
expectedErr: true,
},
}
for _, test := range tests {
meta := metav1.ObjectMeta{Name: "foo", Namespace: metav1.NamespaceDefault, ResourceVersion: "1"}
from := &extensions.Deployment{
ObjectMeta: meta,
Status: test.from,
}
to := &extensions.Deployment{
ObjectMeta: meta,
Status: test.to,
}
errs := ValidateDeploymentStatusUpdate(to, from)
if hasErr := len(errs) > 0; hasErr != test.expectedErr {
errString := spew.Sprintf("%#v", errs)
t.Errorf("%s: expected error: %t, got error: %t\nerrors: %s", test.name, test.expectedErr, hasErr, errString)
} }
} }
} }
......
...@@ -378,6 +378,11 @@ func DeepCopy_extensions_DeploymentStatus(in interface{}, out interface{}, c *co ...@@ -378,6 +378,11 @@ func DeepCopy_extensions_DeploymentStatus(in interface{}, out interface{}, c *co
} }
} }
} }
if in.CollisionCount != nil {
in, out := &in.CollisionCount, &out.CollisionCount
*out = new(int64)
**out = **in
}
return nil return nil
} }
} }
......
...@@ -574,7 +574,6 @@ func (dc *DeploymentController) syncDeployment(key string) error { ...@@ -574,7 +574,6 @@ func (dc *DeploymentController) syncDeployment(key string) error {
return nil return nil
} }
if err != nil { if err != nil {
utilruntime.HandleError(fmt.Errorf("Unable to retrieve deployment %v from store: %v", key, err))
return err return err
} }
......
...@@ -73,7 +73,11 @@ func (dc *DeploymentController) rollback(d *extensions.Deployment, rsList []*ext ...@@ -73,7 +73,11 @@ func (dc *DeploymentController) rollback(d *extensions.Deployment, rsList []*ext
// cleans up the rollback spec so subsequent requeues of the deployment won't end up in here. // cleans up the rollback spec so subsequent requeues of the deployment won't end up in here.
func (dc *DeploymentController) rollbackToTemplate(d *extensions.Deployment, rs *extensions.ReplicaSet) (bool, error) { func (dc *DeploymentController) rollbackToTemplate(d *extensions.Deployment, rs *extensions.ReplicaSet) (bool, error) {
performedRollback := false performedRollback := false
if !deploymentutil.EqualIgnoreHash(d.Spec.Template, rs.Spec.Template) { isEqual, err := deploymentutil.EqualIgnoreHash(&d.Spec.Template, &rs.Spec.Template)
if err != nil {
return false, err
}
if !isEqual {
glog.V(4).Infof("Rolling back deployment %q to template spec %+v", d.Name, rs.Spec.Template.Spec) glog.V(4).Infof("Rolling back deployment %q to template spec %+v", d.Name, rs.Spec.Template.Spec)
deploymentutil.SetFromReplicaSetTemplate(d, rs.Spec.Template) deploymentutil.SetFromReplicaSetTemplate(d, rs.Spec.Template)
// set RS (the old RS we'll rolling back to) annotations back to the deployment; // set RS (the old RS we'll rolling back to) annotations back to the deployment;
......
...@@ -48,6 +48,7 @@ go_test( ...@@ -48,6 +48,7 @@ go_test(
srcs = [ srcs = [
"deployment_util_test.go", "deployment_util_test.go",
"hash_test.go", "hash_test.go",
"pod_util_test.go",
], ],
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
...@@ -57,6 +58,7 @@ go_test( ...@@ -57,6 +58,7 @@ go_test(
"//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/client/clientset_generated/clientset/fake:go_default_library", "//pkg/client/clientset_generated/clientset/fake:go_default_library",
"//pkg/controller:go_default_library", "//pkg/controller:go_default_library",
"//pkg/util/hash:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
......
...@@ -640,29 +640,42 @@ func ListPods(deployment *extensions.Deployment, rsList []*extensions.ReplicaSet ...@@ -640,29 +640,42 @@ func ListPods(deployment *extensions.Deployment, rsList []*extensions.ReplicaSet
// We ignore pod-template-hash because the hash result would be different upon podTemplateSpec API changes // We ignore pod-template-hash because the hash result would be different upon podTemplateSpec API changes
// (e.g. the addition of a new field will cause the hash code to change) // (e.g. the addition of a new field will cause the hash code to change)
// Note that we assume input podTemplateSpecs contain non-empty labels // Note that we assume input podTemplateSpecs contain non-empty labels
func EqualIgnoreHash(template1, template2 v1.PodTemplateSpec) bool { func EqualIgnoreHash(template1, template2 *v1.PodTemplateSpec) (bool, error) {
cp, err := api.Scheme.DeepCopy(template1)
if err != nil {
return false, err
}
t1Copy := cp.(*v1.PodTemplateSpec)
cp, err = api.Scheme.DeepCopy(template2)
if err != nil {
return false, err
}
t2Copy := cp.(*v1.PodTemplateSpec)
// First, compare template.Labels (ignoring hash) // First, compare template.Labels (ignoring hash)
labels1, labels2 := template1.Labels, template2.Labels labels1, labels2 := t1Copy.Labels, t2Copy.Labels
if len(labels1) > len(labels2) { if len(labels1) > len(labels2) {
labels1, labels2 = labels2, labels1 labels1, labels2 = labels2, labels1
} }
// We make sure len(labels2) >= len(labels1) // We make sure len(labels2) >= len(labels1)
for k, v := range labels2 { for k, v := range labels2 {
if labels1[k] != v && k != extensions.DefaultDeploymentUniqueLabelKey { if labels1[k] != v && k != extensions.DefaultDeploymentUniqueLabelKey {
return false return false, nil
} }
} }
// Then, compare the templates without comparing their labels // Then, compare the templates without comparing their labels
template1.Labels, template2.Labels = nil, nil t1Copy.Labels, t2Copy.Labels = nil, nil
return apiequality.Semantic.DeepEqual(template1, template2) return apiequality.Semantic.DeepEqual(t1Copy, t2Copy), nil
} }
// FindNewReplicaSet returns the new RS this given deployment targets (the one with the same pod template). // FindNewReplicaSet returns the new RS this given deployment targets (the one with the same pod template).
func FindNewReplicaSet(deployment *extensions.Deployment, rsList []*extensions.ReplicaSet) (*extensions.ReplicaSet, error) { func FindNewReplicaSet(deployment *extensions.Deployment, rsList []*extensions.ReplicaSet) (*extensions.ReplicaSet, error) {
newRSTemplate := GetNewReplicaSetTemplate(deployment)
sort.Sort(controller.ReplicaSetsByCreationTimestamp(rsList)) sort.Sort(controller.ReplicaSetsByCreationTimestamp(rsList))
for i := range rsList { for i := range rsList {
if EqualIgnoreHash(rsList[i].Spec.Template, newRSTemplate) { equal, err := EqualIgnoreHash(&rsList[i].Spec.Template, &deployment.Spec.Template)
if err != nil {
return nil, err
}
if equal {
// In rare cases, such as after cluster upgrades, Deployment may end up with // In rare cases, such as after cluster upgrades, Deployment may end up with
// having more than one new ReplicaSets that have the same template as its template, // having more than one new ReplicaSets that have the same template as its template,
// see https://github.com/kubernetes/kubernetes/issues/40415 // see https://github.com/kubernetes/kubernetes/issues/40415
...@@ -746,31 +759,6 @@ func LabelPodsWithHash(podList *v1.PodList, c clientset.Interface, podLister cor ...@@ -746,31 +759,6 @@ func LabelPodsWithHash(podList *v1.PodList, c clientset.Interface, podLister cor
return nil return nil
} }
// GetNewReplicaSetTemplate returns the desired PodTemplateSpec for the new ReplicaSet corresponding to the given ReplicaSet.
// Callers of this helper need to set the DefaultDeploymentUniqueLabelKey k/v pair.
func GetNewReplicaSetTemplate(deployment *extensions.Deployment) v1.PodTemplateSpec {
// newRS will have the same template as in deployment spec.
return v1.PodTemplateSpec{
ObjectMeta: deployment.Spec.Template.ObjectMeta,
Spec: deployment.Spec.Template.Spec,
}
}
// TODO: remove the duplicate
// GetNewReplicaSetTemplateInternal returns the desired PodTemplateSpec for the new ReplicaSet corresponding to the given ReplicaSet.
func GetNewReplicaSetTemplateInternal(deployment *internalextensions.Deployment) api.PodTemplateSpec {
// newRS will have the same template as in deployment spec, plus a unique label in some cases.
newRSTemplate := api.PodTemplateSpec{
ObjectMeta: deployment.Spec.Template.ObjectMeta,
Spec: deployment.Spec.Template.Spec,
}
newRSTemplate.ObjectMeta.Labels = labelsutil.CloneAndAddLabel(
deployment.Spec.Template.ObjectMeta.Labels,
internalextensions.DefaultDeploymentUniqueLabelKey,
fmt.Sprintf("%d", GetInternalPodTemplateSpecHash(newRSTemplate)))
return newRSTemplate
}
// SetFromReplicaSetTemplate sets the desired PodTemplateSpec from a replica set template to the given deployment. // SetFromReplicaSetTemplate sets the desired PodTemplateSpec from a replica set template to the given deployment.
func SetFromReplicaSetTemplate(deployment *extensions.Deployment, template v1.PodTemplateSpec) *extensions.Deployment { func SetFromReplicaSetTemplate(deployment *extensions.Deployment, template v1.PodTemplateSpec) *extensions.Deployment {
deployment.Spec.Template.ObjectMeta = template.ObjectMeta deployment.Spec.Template.ObjectMeta = template.ObjectMeta
......
...@@ -184,7 +184,8 @@ func newDControllerRef(d *extensions.Deployment) *metav1.OwnerReference { ...@@ -184,7 +184,8 @@ func newDControllerRef(d *extensions.Deployment) *metav1.OwnerReference {
// generateRS creates a replica set, with the input deployment's template as its template // generateRS creates a replica set, with the input deployment's template as its template
func generateRS(deployment extensions.Deployment) extensions.ReplicaSet { func generateRS(deployment extensions.Deployment) extensions.ReplicaSet {
template := GetNewReplicaSetTemplate(&deployment) cp, _ := api.Scheme.DeepCopy(deployment.Spec.Template)
template := cp.(v1.PodTemplateSpec)
return extensions.ReplicaSet{ return extensions.ReplicaSet{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
UID: randomUID(), UID: randomUID(),
...@@ -193,7 +194,7 @@ func generateRS(deployment extensions.Deployment) extensions.ReplicaSet { ...@@ -193,7 +194,7 @@ func generateRS(deployment extensions.Deployment) extensions.ReplicaSet {
OwnerReferences: []metav1.OwnerReference{*newDControllerRef(&deployment)}, OwnerReferences: []metav1.OwnerReference{*newDControllerRef(&deployment)},
}, },
Spec: extensions.ReplicaSetSpec{ Spec: extensions.ReplicaSetSpec{
Replicas: func() *int32 { i := int32(0); return &i }(), Replicas: new(int32),
Template: template, Template: template,
Selector: &metav1.LabelSelector{MatchLabels: template.Labels}, Selector: &metav1.LabelSelector{MatchLabels: template.Labels},
}, },
...@@ -444,29 +445,22 @@ func TestEqualIgnoreHash(t *testing.T) { ...@@ -444,29 +445,22 @@ func TestEqualIgnoreHash(t *testing.T) {
for _, test := range tests { for _, test := range tests {
runTest := func(t1, t2 *v1.PodTemplateSpec, reversed bool) { runTest := func(t1, t2 *v1.PodTemplateSpec, reversed bool) {
// Set up
t1Copy, err := api.Scheme.DeepCopy(t1)
if err != nil {
t.Errorf("Failed setting up the test: %v", err)
}
t2Copy, err := api.Scheme.DeepCopy(t2)
if err != nil {
t.Errorf("Failed setting up the test: %v", err)
}
reverseString := "" reverseString := ""
if reversed { if reversed {
reverseString = " (reverse order)" reverseString = " (reverse order)"
} }
// Run // Run
equal := EqualIgnoreHash(*t1, *t2) equal, err := EqualIgnoreHash(t1, t2)
if err != nil {
t.Errorf("%s: unexpected error: %v", err, test.test)
return
}
if equal != test.expected { if equal != test.expected {
t.Errorf("In test case %q%s, expected %v", test.test, reverseString, test.expected) t.Errorf("%q%s: expected %v", test.test, reverseString, test.expected)
return
} }
if t1.Labels == nil || t2.Labels == nil { if t1.Labels == nil || t2.Labels == nil {
t.Errorf("In test case %q%s, unexpected labels becomes nil", test.test, reverseString) t.Errorf("%q%s: unexpected labels becomes nil", test.test, reverseString)
}
if !reflect.DeepEqual(t1, t1Copy) || !reflect.DeepEqual(t2, t2Copy) {
t.Errorf("In test case %q%s, unexpected input template modified", test.test, reverseString)
} }
} }
runTest(&test.former, &test.latter, false) runTest(&test.former, &test.latter, false)
......
...@@ -18,11 +18,13 @@ package util ...@@ -18,11 +18,13 @@ package util
import ( import (
"encoding/json" "encoding/json"
"hash/adler32"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
hashutil "k8s.io/kubernetes/pkg/util/hash"
) )
var podSpec string = ` var podSpec string = `
...@@ -103,34 +105,12 @@ var podSpec string = ` ...@@ -103,34 +105,12 @@ var podSpec string = `
func TestPodTemplateSpecHash(t *testing.T) { func TestPodTemplateSpecHash(t *testing.T) {
seenHashes := make(map[uint32]int) seenHashes := make(map[uint32]int)
broken := false
for i := 0; i < 1000; i++ { for i := 0; i < 1000; i++ {
specJson := strings.Replace(podSpec, "@@VERSION@@", strconv.Itoa(i), 1) specJson := strings.Replace(podSpec, "@@VERSION@@", strconv.Itoa(i), 1)
spec := v1.PodTemplateSpec{} spec := v1.PodTemplateSpec{}
json.Unmarshal([]byte(specJson), &spec) json.Unmarshal([]byte(specJson), &spec)
hash := GetPodTemplateSpecHash(spec) hash := GetPodTemplateSpecHash(&spec, nil)
if v, ok := seenHashes[hash]; ok {
broken = true
t.Logf("Hash collision, old: %d new: %d", v, i)
break
}
seenHashes[hash] = i
}
if !broken {
t.Errorf("expected adler to break but it didn't")
}
}
func TestPodTemplateSpecHashFnv(t *testing.T) {
seenHashes := make(map[uint32]int)
for i := 0; i < 1000; i++ {
specJson := strings.Replace(podSpec, "@@VERSION@@", strconv.Itoa(i), 1)
spec := v1.PodTemplateSpec{}
json.Unmarshal([]byte(specJson), &spec)
hash := GetPodTemplateSpecHashFnv(spec)
if v, ok := seenHashes[hash]; ok { if v, ok := seenHashes[hash]; ok {
t.Errorf("Hash collision, old: %d new: %d", v, i) t.Errorf("Hash collision, old: %d new: %d", v, i)
break break
...@@ -144,15 +124,21 @@ func BenchmarkAdler(b *testing.B) { ...@@ -144,15 +124,21 @@ func BenchmarkAdler(b *testing.B) {
json.Unmarshal([]byte(podSpec), &spec) json.Unmarshal([]byte(podSpec), &spec)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
GetPodTemplateSpecHash(spec) getPodTemplateSpecOldHash(spec)
} }
} }
func getPodTemplateSpecOldHash(template v1.PodTemplateSpec) uint32 {
podTemplateSpecHasher := adler32.New()
hashutil.DeepHashObject(podTemplateSpecHasher, template)
return podTemplateSpecHasher.Sum32()
}
func BenchmarkFnv(b *testing.B) { func BenchmarkFnv(b *testing.B) {
spec := v1.PodTemplateSpec{} spec := v1.PodTemplateSpec{}
json.Unmarshal([]byte(podSpec), &spec) json.Unmarshal([]byte(podSpec), &spec)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
GetPodTemplateSpecHashFnv(spec) GetPodTemplateSpecHash(&spec, nil)
} }
} }
...@@ -17,7 +17,7 @@ limitations under the License. ...@@ -17,7 +17,7 @@ limitations under the License.
package util package util
import ( import (
"hash/adler32" "encoding/binary"
"hash/fnv" "hash/fnv"
"github.com/golang/glog" "github.com/golang/glog"
...@@ -31,22 +31,17 @@ import ( ...@@ -31,22 +31,17 @@ import (
hashutil "k8s.io/kubernetes/pkg/util/hash" hashutil "k8s.io/kubernetes/pkg/util/hash"
) )
func GetPodTemplateSpecHash(template v1.PodTemplateSpec) uint32 { func GetPodTemplateSpecHash(template *v1.PodTemplateSpec, uniquifier *int64) uint32 {
podTemplateSpecHasher := adler32.New() podTemplateSpecHasher := fnv.New32a()
hashutil.DeepHashObject(podTemplateSpecHasher, template) hashutil.DeepHashObject(podTemplateSpecHasher, *template)
return podTemplateSpecHasher.Sum32()
}
// TODO: remove the duplicate // Add uniquifier in the hash if it exists.
func GetInternalPodTemplateSpecHash(template api.PodTemplateSpec) uint32 { if uniquifier != nil {
podTemplateSpecHasher := adler32.New() uniquifierBytes := make([]byte, 8)
hashutil.DeepHashObject(podTemplateSpecHasher, template) binary.LittleEndian.PutUint64(uniquifierBytes, uint64(*uniquifier))
return podTemplateSpecHasher.Sum32() podTemplateSpecHasher.Write(uniquifierBytes)
} }
func GetPodTemplateSpecHashFnv(template v1.PodTemplateSpec) uint32 {
podTemplateSpecHasher := fnv.New32a()
hashutil.DeepHashObject(podTemplateSpecHasher, template)
return podTemplateSpecHasher.Sum32() return podTemplateSpecHasher.Sum32()
} }
......
/*
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 (
"math"
"testing"
"k8s.io/kubernetes/pkg/api/v1"
)
func int64P(num int64) *int64 {
return &num
}
func TestGetPodTemplateSpecHash(t *testing.T) {
tests := []struct {
name string
template *v1.PodTemplateSpec
collisionCount *int64
otherCollisionCount *int64
}{
{
name: "simple",
template: &v1.PodTemplateSpec{},
collisionCount: int64P(1),
otherCollisionCount: int64P(2),
},
{
name: "using math.MaxInt64",
template: &v1.PodTemplateSpec{},
collisionCount: nil,
otherCollisionCount: int64P(int64(math.MaxInt64)),
},
}
for _, test := range tests {
hash := GetPodTemplateSpecHash(test.template, test.collisionCount)
otherHash := GetPodTemplateSpecHash(test.template, test.otherCollisionCount)
if hash == otherHash {
t.Errorf("expected different hashes but got the same: %d", hash)
}
}
}
...@@ -69,21 +69,12 @@ func UpdateRSWithRetries(rsClient unversionedextensions.ReplicaSetInterface, rsL ...@@ -69,21 +69,12 @@ func UpdateRSWithRetries(rsClient unversionedextensions.ReplicaSetInterface, rsL
} }
// GetReplicaSetHash returns the pod template hash of a ReplicaSet's pod template space // GetReplicaSetHash returns the pod template hash of a ReplicaSet's pod template space
func GetReplicaSetHash(rs *extensions.ReplicaSet) string { func GetReplicaSetHash(rs *extensions.ReplicaSet, uniquifier *int64) (string, error) {
meta := rs.Spec.Template.ObjectMeta template, err := api.Scheme.DeepCopy(rs.Spec.Template)
meta.Labels = labelsutil.CloneAndRemoveLabel(meta.Labels, extensions.DefaultDeploymentUniqueLabelKey) if err != nil {
return fmt.Sprintf("%d", GetPodTemplateSpecHash(v1.PodTemplateSpec{ return "", err
ObjectMeta: meta, }
Spec: rs.Spec.Template.Spec, rsTemplate := template.(v1.PodTemplateSpec)
})) rsTemplate.Labels = labelsutil.CloneAndRemoveLabel(rsTemplate.Labels, extensions.DefaultDeploymentUniqueLabelKey)
} return fmt.Sprintf("%d", GetPodTemplateSpecHash(&rsTemplate, uniquifier)), nil
// GetReplicaSetHashFnv returns the pod template hash of a ReplicaSet's pod template spec.
func GetReplicaSetHashFnv(rs *extensions.ReplicaSet) string {
meta := rs.Spec.Template.ObjectMeta
meta.Labels = labelsutil.CloneAndRemoveLabel(meta.Labels, extensions.DefaultDeploymentUniqueLabelKey)
return fmt.Sprintf("%d", GetPodTemplateSpecHashFnv(v1.PodTemplateSpec{
ObjectMeta: meta,
Spec: rs.Spec.Template.Spec,
}))
} }
...@@ -157,7 +157,6 @@ go_test( ...@@ -157,7 +157,6 @@ go_test(
"//pkg/client/clientset_generated/internalclientset/typed/batch/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/batch/internalversion:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library",
"//pkg/controller/deployment/util:go_default_library",
"//pkg/kubectl/util:go_default_library", "//pkg/kubectl/util:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
......
...@@ -35,7 +35,6 @@ import ( ...@@ -35,7 +35,6 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
) )
func TestReplicationControllerStop(t *testing.T) { func TestReplicationControllerStop(t *testing.T) {
...@@ -441,7 +440,6 @@ func TestDeploymentStop(t *testing.T) { ...@@ -441,7 +440,6 @@ func TestDeploymentStop(t *testing.T) {
Replicas: 0, Replicas: 0,
}, },
} }
template := deploymentutil.GetNewReplicaSetTemplateInternal(&deployment)
trueVar := true trueVar := true
tests := []struct { tests := []struct {
Name string Name string
...@@ -492,9 +490,7 @@ func TestDeploymentStop(t *testing.T) { ...@@ -492,9 +490,7 @@ func TestDeploymentStop(t *testing.T) {
}, },
}, },
}, },
Spec: extensions.ReplicaSetSpec{ Spec: extensions.ReplicaSetSpec{},
Template: template,
},
}, },
// ReplicaSet owned by something else (should be ignored). // ReplicaSet owned by something else (should be ignored).
{ {
...@@ -512,9 +508,7 @@ func TestDeploymentStop(t *testing.T) { ...@@ -512,9 +508,7 @@ func TestDeploymentStop(t *testing.T) {
}, },
}, },
}, },
Spec: extensions.ReplicaSetSpec{ Spec: extensions.ReplicaSetSpec{},
Template: template,
},
}, },
}, },
}, },
...@@ -709,7 +703,6 @@ func TestDeploymentNotFoundError(t *testing.T) { ...@@ -709,7 +703,6 @@ func TestDeploymentNotFoundError(t *testing.T) {
Replicas: 0, Replicas: 0,
}, },
} }
template := deploymentutil.GetNewReplicaSetTemplateInternal(deployment)
fake := fake.NewSimpleClientset( fake := fake.NewSimpleClientset(
deployment, deployment,
...@@ -719,9 +712,7 @@ func TestDeploymentNotFoundError(t *testing.T) { ...@@ -719,9 +712,7 @@ func TestDeploymentNotFoundError(t *testing.T) {
Name: name, Name: name,
Namespace: ns, Namespace: ns,
}, },
Spec: extensions.ReplicaSetSpec{ Spec: extensions.ReplicaSetSpec{},
Template: template,
},
}, },
}, },
}, },
......
{ {
"ImportPath": "k8s.io/client-go", "ImportPath": "k8s.io/client-go",
"GoVersion": "go1.7", "GoVersion": "go1.8",
"GodepVersion": "v79", "GodepVersion": "v79",
"Packages": [ "Packages": [
"./..." "./..."
......
...@@ -170,6 +170,12 @@ message DeploymentStatus { ...@@ -170,6 +170,12 @@ message DeploymentStatus {
// +patchMergeKey=type // +patchMergeKey=type
// +patchStrategy=merge // +patchStrategy=merge
repeated DeploymentCondition conditions = 6; repeated DeploymentCondition conditions = 6;
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
optional int64 collisionCount = 8;
} }
// DeploymentStrategy describes how to replace existing pods with new ones. // DeploymentStrategy describes how to replace existing pods with new ones.
......
...@@ -4672,7 +4672,7 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -4672,7 +4672,7 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} else { } else {
yysep2 := !z.EncBinary() yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [7]bool var yyq2 [8]bool
_, _, _ = yysep2, yyq2, yy2arr2 _, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false const yyr2 bool = false
yyq2[0] = x.ObservedGeneration != 0 yyq2[0] = x.ObservedGeneration != 0
...@@ -4682,9 +4682,10 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -4682,9 +4682,10 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
yyq2[4] = x.AvailableReplicas != 0 yyq2[4] = x.AvailableReplicas != 0
yyq2[5] = x.UnavailableReplicas != 0 yyq2[5] = x.UnavailableReplicas != 0
yyq2[6] = len(x.Conditions) != 0 yyq2[6] = len(x.Conditions) != 0
yyq2[7] = x.CollisionCount != nil
var yynn2 int var yynn2 int
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
r.EncodeArrayStart(7) r.EncodeArrayStart(8)
} else { } else {
yynn2 = 0 yynn2 = 0
for _, b := range yyq2 { for _, b := range yyq2 {
...@@ -4879,6 +4880,41 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -4879,6 +4880,41 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} }
} }
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[7] {
if x.CollisionCount == nil {
r.EncodeNil()
} else {
yy25 := *x.CollisionCount
yym26 := z.EncBinary()
_ = yym26
if false {
} else {
r.EncodeInt(int64(yy25))
}
}
} else {
r.EncodeNil()
}
} else {
if yyq2[7] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("collisionCount"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
if x.CollisionCount == nil {
r.EncodeNil()
} else {
yy27 := *x.CollisionCount
yym28 := z.EncBinary()
_ = yym28
if false {
} else {
r.EncodeInt(int64(yy27))
}
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234) z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else { } else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234) z.EncSendContainerState(codecSelfer_containerMapEnd1234)
...@@ -5023,6 +5059,22 @@ func (x *DeploymentStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { ...@@ -5023,6 +5059,22 @@ func (x *DeploymentStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv16), d) h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv16), d)
} }
} }
case "collisionCount":
if r.TryDecodeAsNil() {
if x.CollisionCount != nil {
x.CollisionCount = nil
}
} else {
if x.CollisionCount == nil {
x.CollisionCount = new(int64)
}
yym19 := z.DecBinary()
_ = yym19
if false {
} else {
*((*int64)(x.CollisionCount)) = int64(r.DecodeInt(64))
}
}
default: default:
z.DecStructFieldNotFound(-1, yys3) z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3 } // end switch yys3
...@@ -5034,16 +5086,16 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5034,16 +5086,16 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
var yyj18 int var yyj20 int
var yyb18 bool var yyb20 bool
var yyhl18 bool = l >= 0 var yyhl20 bool = l >= 0
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5051,21 +5103,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5051,21 +5103,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ObservedGeneration = 0 x.ObservedGeneration = 0
} else { } else {
yyv19 := &x.ObservedGeneration yyv21 := &x.ObservedGeneration
yym20 := z.DecBinary() yym22 := z.DecBinary()
_ = yym20 _ = yym22
if false { if false {
} else { } else {
*((*int64)(yyv19)) = int64(r.DecodeInt(64)) *((*int64)(yyv21)) = int64(r.DecodeInt(64))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5073,21 +5125,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5073,21 +5125,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Replicas = 0 x.Replicas = 0
} else { } else {
yyv21 := &x.Replicas yyv23 := &x.Replicas
yym22 := z.DecBinary() yym24 := z.DecBinary()
_ = yym22 _ = yym24
if false { if false {
} else { } else {
*((*int32)(yyv21)) = int32(r.DecodeInt(32)) *((*int32)(yyv23)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5095,21 +5147,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5095,21 +5147,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.UpdatedReplicas = 0 x.UpdatedReplicas = 0
} else { } else {
yyv23 := &x.UpdatedReplicas yyv25 := &x.UpdatedReplicas
yym24 := z.DecBinary() yym26 := z.DecBinary()
_ = yym24 _ = yym26
if false { if false {
} else { } else {
*((*int32)(yyv23)) = int32(r.DecodeInt(32)) *((*int32)(yyv25)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5117,21 +5169,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5117,21 +5169,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ReadyReplicas = 0 x.ReadyReplicas = 0
} else { } else {
yyv25 := &x.ReadyReplicas yyv27 := &x.ReadyReplicas
yym26 := z.DecBinary() yym28 := z.DecBinary()
_ = yym26 _ = yym28
if false { if false {
} else { } else {
*((*int32)(yyv25)) = int32(r.DecodeInt(32)) *((*int32)(yyv27)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5139,21 +5191,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5139,21 +5191,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.AvailableReplicas = 0 x.AvailableReplicas = 0
} else { } else {
yyv27 := &x.AvailableReplicas yyv29 := &x.AvailableReplicas
yym28 := z.DecBinary() yym30 := z.DecBinary()
_ = yym28 _ = yym30
if false { if false {
} else { } else {
*((*int32)(yyv27)) = int32(r.DecodeInt(32)) *((*int32)(yyv29)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5161,21 +5213,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5161,21 +5213,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.UnavailableReplicas = 0 x.UnavailableReplicas = 0
} else { } else {
yyv29 := &x.UnavailableReplicas yyv31 := &x.UnavailableReplicas
yym30 := z.DecBinary() yym32 := z.DecBinary()
_ = yym30 _ = yym32
if false { if false {
} else { } else {
*((*int32)(yyv29)) = int32(r.DecodeInt(32)) *((*int32)(yyv31)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5183,26 +5235,52 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5183,26 +5235,52 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Conditions = nil x.Conditions = nil
} else { } else {
yyv31 := &x.Conditions yyv33 := &x.Conditions
yym32 := z.DecBinary() yym34 := z.DecBinary()
_ = yym32 _ = yym34
if false {
} else {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv33), d)
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
if x.CollisionCount != nil {
x.CollisionCount = nil
}
} else {
if x.CollisionCount == nil {
x.CollisionCount = new(int64)
}
yym36 := z.DecBinary()
_ = yym36
if false { if false {
} else { } else {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv31), d) *((*int64)(x.CollisionCount)) = int64(r.DecodeInt(64))
} }
} }
for { for {
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
break break
} }
z.DecSendContainerState(codecSelfer_containerArrayElem1234) z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj18-1, "") z.DecStructFieldNotFound(yyj20-1, "")
} }
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} }
...@@ -6470,7 +6548,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode ...@@ -6470,7 +6548,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode
yyrg1 := len(yyv1) > 0 yyrg1 := len(yyv1) > 0
yyv21 := yyv1 yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 960) yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 968)
if yyrt1 { if yyrt1 {
if yyrl1 <= cap(yyv1) { if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1] yyv1 = yyv1[:yyrl1]
......
...@@ -356,6 +356,12 @@ type DeploymentStatus struct { ...@@ -356,6 +356,12 @@ type DeploymentStatus struct {
// +patchMergeKey=type // +patchMergeKey=type
// +patchStrategy=merge // +patchStrategy=merge
Conditions []DeploymentCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,6,rep,name=conditions"` Conditions []DeploymentCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,6,rep,name=conditions"`
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
CollisionCount *int64 `json:"collisionCount,omitempty" protobuf:"varint,8,opt,name=collisionCount"`
} }
type DeploymentConditionType string type DeploymentConditionType string
......
...@@ -99,6 +99,7 @@ var map_DeploymentStatus = map[string]string{ ...@@ -99,6 +99,7 @@ var map_DeploymentStatus = map[string]string{
"availableReplicas": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.", "availableReplicas": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.",
"unavailableReplicas": "Total number of unavailable pods targeted by this deployment.", "unavailableReplicas": "Total number of unavailable pods targeted by this deployment.",
"conditions": "Represents the latest available observations of a deployment's current state.", "conditions": "Represents the latest available observations of a deployment's current state.",
"collisionCount": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.",
} }
func (DeploymentStatus) SwaggerDoc() map[string]string { func (DeploymentStatus) SwaggerDoc() map[string]string {
......
...@@ -184,6 +184,11 @@ func DeepCopy_v1beta1_DeploymentStatus(in interface{}, out interface{}, c *conve ...@@ -184,6 +184,11 @@ func DeepCopy_v1beta1_DeploymentStatus(in interface{}, out interface{}, c *conve
} }
} }
} }
if in.CollisionCount != nil {
in, out := &in.CollisionCount, &out.CollisionCount
*out = new(int64)
**out = **in
}
return nil return nil
} }
} }
......
...@@ -327,6 +327,12 @@ type DeploymentStatus struct { ...@@ -327,6 +327,12 @@ type DeploymentStatus struct {
// Represents the latest available observations of a deployment's current state. // Represents the latest available observations of a deployment's current state.
Conditions []DeploymentCondition Conditions []DeploymentCondition
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
CollisionCount *int64
} }
type DeploymentConditionType string type DeploymentConditionType string
......
...@@ -325,6 +325,12 @@ message DeploymentStatus { ...@@ -325,6 +325,12 @@ message DeploymentStatus {
// +patchMergeKey=type // +patchMergeKey=type
// +patchStrategy=merge // +patchStrategy=merge
repeated DeploymentCondition conditions = 6; repeated DeploymentCondition conditions = 6;
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
optional int64 collisionCount = 8;
} }
// DeploymentStrategy describes how to replace existing pods with new ones. // DeploymentStrategy describes how to replace existing pods with new ones.
......
...@@ -5606,7 +5606,7 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -5606,7 +5606,7 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} else { } else {
yysep2 := !z.EncBinary() yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [7]bool var yyq2 [8]bool
_, _, _ = yysep2, yyq2, yy2arr2 _, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false const yyr2 bool = false
yyq2[0] = x.ObservedGeneration != 0 yyq2[0] = x.ObservedGeneration != 0
...@@ -5616,9 +5616,10 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -5616,9 +5616,10 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
yyq2[4] = x.AvailableReplicas != 0 yyq2[4] = x.AvailableReplicas != 0
yyq2[5] = x.UnavailableReplicas != 0 yyq2[5] = x.UnavailableReplicas != 0
yyq2[6] = len(x.Conditions) != 0 yyq2[6] = len(x.Conditions) != 0
yyq2[7] = x.CollisionCount != nil
var yynn2 int var yynn2 int
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
r.EncodeArrayStart(7) r.EncodeArrayStart(8)
} else { } else {
yynn2 = 0 yynn2 = 0
for _, b := range yyq2 { for _, b := range yyq2 {
...@@ -5813,6 +5814,41 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) { ...@@ -5813,6 +5814,41 @@ func (x *DeploymentStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} }
} }
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[7] {
if x.CollisionCount == nil {
r.EncodeNil()
} else {
yy25 := *x.CollisionCount
yym26 := z.EncBinary()
_ = yym26
if false {
} else {
r.EncodeInt(int64(yy25))
}
}
} else {
r.EncodeNil()
}
} else {
if yyq2[7] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("collisionCount"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
if x.CollisionCount == nil {
r.EncodeNil()
} else {
yy27 := *x.CollisionCount
yym28 := z.EncBinary()
_ = yym28
if false {
} else {
r.EncodeInt(int64(yy27))
}
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234) z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else { } else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234) z.EncSendContainerState(codecSelfer_containerMapEnd1234)
...@@ -5957,6 +5993,22 @@ func (x *DeploymentStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { ...@@ -5957,6 +5993,22 @@ func (x *DeploymentStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv16), d) h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv16), d)
} }
} }
case "collisionCount":
if r.TryDecodeAsNil() {
if x.CollisionCount != nil {
x.CollisionCount = nil
}
} else {
if x.CollisionCount == nil {
x.CollisionCount = new(int64)
}
yym19 := z.DecBinary()
_ = yym19
if false {
} else {
*((*int64)(x.CollisionCount)) = int64(r.DecodeInt(64))
}
}
default: default:
z.DecStructFieldNotFound(-1, yys3) z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3 } // end switch yys3
...@@ -5968,16 +6020,16 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5968,16 +6020,16 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
var yyj18 int var yyj20 int
var yyb18 bool var yyb20 bool
var yyhl18 bool = l >= 0 var yyhl20 bool = l >= 0
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -5985,21 +6037,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -5985,21 +6037,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ObservedGeneration = 0 x.ObservedGeneration = 0
} else { } else {
yyv19 := &x.ObservedGeneration yyv21 := &x.ObservedGeneration
yym20 := z.DecBinary() yym22 := z.DecBinary()
_ = yym20 _ = yym22
if false { if false {
} else { } else {
*((*int64)(yyv19)) = int64(r.DecodeInt(64)) *((*int64)(yyv21)) = int64(r.DecodeInt(64))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6007,21 +6059,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6007,21 +6059,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Replicas = 0 x.Replicas = 0
} else { } else {
yyv21 := &x.Replicas yyv23 := &x.Replicas
yym22 := z.DecBinary() yym24 := z.DecBinary()
_ = yym22 _ = yym24
if false { if false {
} else { } else {
*((*int32)(yyv21)) = int32(r.DecodeInt(32)) *((*int32)(yyv23)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6029,21 +6081,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6029,21 +6081,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.UpdatedReplicas = 0 x.UpdatedReplicas = 0
} else { } else {
yyv23 := &x.UpdatedReplicas yyv25 := &x.UpdatedReplicas
yym24 := z.DecBinary() yym26 := z.DecBinary()
_ = yym24 _ = yym26
if false { if false {
} else { } else {
*((*int32)(yyv23)) = int32(r.DecodeInt(32)) *((*int32)(yyv25)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6051,21 +6103,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6051,21 +6103,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.ReadyReplicas = 0 x.ReadyReplicas = 0
} else { } else {
yyv25 := &x.ReadyReplicas yyv27 := &x.ReadyReplicas
yym26 := z.DecBinary() yym28 := z.DecBinary()
_ = yym26 _ = yym28
if false { if false {
} else { } else {
*((*int32)(yyv25)) = int32(r.DecodeInt(32)) *((*int32)(yyv27)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6073,21 +6125,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6073,21 +6125,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.AvailableReplicas = 0 x.AvailableReplicas = 0
} else { } else {
yyv27 := &x.AvailableReplicas yyv29 := &x.AvailableReplicas
yym28 := z.DecBinary() yym30 := z.DecBinary()
_ = yym28 _ = yym30
if false { if false {
} else { } else {
*((*int32)(yyv27)) = int32(r.DecodeInt(32)) *((*int32)(yyv29)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6095,21 +6147,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6095,21 +6147,21 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.UnavailableReplicas = 0 x.UnavailableReplicas = 0
} else { } else {
yyv29 := &x.UnavailableReplicas yyv31 := &x.UnavailableReplicas
yym30 := z.DecBinary() yym32 := z.DecBinary()
_ = yym30 _ = yym32
if false { if false {
} else { } else {
*((*int32)(yyv29)) = int32(r.DecodeInt(32)) *((*int32)(yyv31)) = int32(r.DecodeInt(32))
} }
} }
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
...@@ -6117,26 +6169,52 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) ...@@ -6117,26 +6169,52 @@ func (x *DeploymentStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Conditions = nil x.Conditions = nil
} else { } else {
yyv31 := &x.Conditions yyv33 := &x.Conditions
yym32 := z.DecBinary() yym34 := z.DecBinary()
_ = yym32 _ = yym34
if false {
} else {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv33), d)
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
if x.CollisionCount != nil {
x.CollisionCount = nil
}
} else {
if x.CollisionCount == nil {
x.CollisionCount = new(int64)
}
yym36 := z.DecBinary()
_ = yym36
if false { if false {
} else { } else {
h.decSliceDeploymentCondition((*[]DeploymentCondition)(yyv31), d) *((*int64)(x.CollisionCount)) = int64(r.DecodeInt(64))
} }
} }
for { for {
yyj18++ yyj20++
if yyhl18 { if yyhl20 {
yyb18 = yyj18 > l yyb20 = yyj20 > l
} else { } else {
yyb18 = r.CheckBreak() yyb20 = r.CheckBreak()
} }
if yyb18 { if yyb20 {
break break
} }
z.DecSendContainerState(codecSelfer_containerArrayElem1234) z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj18-1, "") z.DecStructFieldNotFound(yyj20-1, "")
} }
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} }
...@@ -19652,7 +19730,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode ...@@ -19652,7 +19730,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode
yyrg1 := len(yyv1) > 0 yyrg1 := len(yyv1) > 0
yyv21 := yyv1 yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 960) yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 968)
if yyrt1 { if yyrt1 {
if yyrl1 <= cap(yyv1) { if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1] yyv1 = yyv1[:yyrl1]
......
...@@ -325,6 +325,12 @@ type DeploymentStatus struct { ...@@ -325,6 +325,12 @@ type DeploymentStatus struct {
// +patchMergeKey=type // +patchMergeKey=type
// +patchStrategy=merge // +patchStrategy=merge
Conditions []DeploymentCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,6,rep,name=conditions"` Conditions []DeploymentCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,6,rep,name=conditions"`
// Count of hash collisions for the Deployment. The Deployment controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest ReplicaSet.
// +optional
CollisionCount *int64 `json:"collisionCount,omitempty" protobuf:"varint,8,opt,name=collisionCount"`
} }
type DeploymentConditionType string type DeploymentConditionType string
......
...@@ -186,6 +186,7 @@ var map_DeploymentStatus = map[string]string{ ...@@ -186,6 +186,7 @@ var map_DeploymentStatus = map[string]string{
"availableReplicas": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.", "availableReplicas": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.",
"unavailableReplicas": "Total number of unavailable pods targeted by this deployment.", "unavailableReplicas": "Total number of unavailable pods targeted by this deployment.",
"conditions": "Represents the latest available observations of a deployment's current state.", "conditions": "Represents the latest available observations of a deployment's current state.",
"collisionCount": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.",
} }
func (DeploymentStatus) SwaggerDoc() map[string]string { func (DeploymentStatus) SwaggerDoc() map[string]string {
......
...@@ -628,6 +628,7 @@ func autoConvert_v1beta1_DeploymentStatus_To_extensions_DeploymentStatus(in *Dep ...@@ -628,6 +628,7 @@ func autoConvert_v1beta1_DeploymentStatus_To_extensions_DeploymentStatus(in *Dep
out.AvailableReplicas = in.AvailableReplicas out.AvailableReplicas = in.AvailableReplicas
out.UnavailableReplicas = in.UnavailableReplicas out.UnavailableReplicas = in.UnavailableReplicas
out.Conditions = *(*[]extensions.DeploymentCondition)(unsafe.Pointer(&in.Conditions)) out.Conditions = *(*[]extensions.DeploymentCondition)(unsafe.Pointer(&in.Conditions))
out.CollisionCount = (*int64)(unsafe.Pointer(in.CollisionCount))
return nil return nil
} }
...@@ -644,6 +645,7 @@ func autoConvert_extensions_DeploymentStatus_To_v1beta1_DeploymentStatus(in *ext ...@@ -644,6 +645,7 @@ func autoConvert_extensions_DeploymentStatus_To_v1beta1_DeploymentStatus(in *ext
out.AvailableReplicas = in.AvailableReplicas out.AvailableReplicas = in.AvailableReplicas
out.UnavailableReplicas = in.UnavailableReplicas out.UnavailableReplicas = in.UnavailableReplicas
out.Conditions = *(*[]DeploymentCondition)(unsafe.Pointer(&in.Conditions)) out.Conditions = *(*[]DeploymentCondition)(unsafe.Pointer(&in.Conditions))
out.CollisionCount = (*int64)(unsafe.Pointer(in.CollisionCount))
return nil return nil
} }
......
...@@ -384,6 +384,11 @@ func DeepCopy_v1beta1_DeploymentStatus(in interface{}, out interface{}, c *conve ...@@ -384,6 +384,11 @@ func DeepCopy_v1beta1_DeploymentStatus(in interface{}, out interface{}, c *conve
} }
} }
} }
if in.CollisionCount != nil {
in, out := &in.CollisionCount, &out.CollisionCount
*out = new(int64)
**out = **in
}
return nil return nil
} }
} }
......
...@@ -378,6 +378,11 @@ func DeepCopy_extensions_DeploymentStatus(in interface{}, out interface{}, c *co ...@@ -378,6 +378,11 @@ func DeepCopy_extensions_DeploymentStatus(in interface{}, out interface{}, c *co
} }
} }
} }
if in.CollisionCount != nil {
in, out := &in.CollisionCount, &out.CollisionCount
*out = new(int64)
**out = **in
}
return nil return nil
} }
} }
......
...@@ -164,6 +164,7 @@ go_library( ...@@ -164,6 +164,7 @@ go_library(
"//test/e2e_federation:go_default_library", "//test/e2e_federation:go_default_library",
"//test/images/net/nat:go_default_library", "//test/images/net/nat:go_default_library",
"//test/utils:go_default_library", "//test/utils:go_default_library",
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
"//vendor/github.com/elazarl/goproxy:go_default_library", "//vendor/github.com/elazarl/goproxy:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library", "//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/golang/glog:go_default_library",
......
...@@ -21,8 +21,10 @@ import ( ...@@ -21,8 +21,10 @@ import (
"math/rand" "math/rand"
"time" "time"
"github.com/davecgh/go-spew/spew"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
...@@ -108,6 +110,9 @@ var _ = framework.KubeDescribe("Deployment", func() { ...@@ -108,6 +110,9 @@ var _ = framework.KubeDescribe("Deployment", func() {
It("test Deployment ReplicaSet orphaning and adoption regarding controllerRef", func() { It("test Deployment ReplicaSet orphaning and adoption regarding controllerRef", func() {
testDeploymentsControllerRef(f) testDeploymentsControllerRef(f)
}) })
It("deployment can avoid hash collisions", func() {
testDeploymentHashCollisionAvoidance(f)
})
// TODO: add tests that cover deployment.Spec.MinReadySeconds once we solved clock-skew issues // TODO: add tests that cover deployment.Spec.MinReadySeconds once we solved clock-skew issues
// See https://github.com/kubernetes/kubernetes/issues/29229 // See https://github.com/kubernetes/kubernetes/issues/29229
}) })
...@@ -1359,3 +1364,47 @@ func orphanDeploymentReplicaSets(c clientset.Interface, d *extensions.Deployment ...@@ -1359,3 +1364,47 @@ func orphanDeploymentReplicaSets(c clientset.Interface, d *extensions.Deployment
deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(d.UID)) deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(d.UID))
return c.Extensions().Deployments(d.Namespace).Delete(d.Name, deleteOptions) return c.Extensions().Deployments(d.Namespace).Delete(d.Name, deleteOptions)
} }
func testDeploymentHashCollisionAvoidance(f *framework.Framework) {
ns := f.Namespace.Name
c := f.ClientSet
deploymentName := "test-hash-collision"
framework.Logf("Creating Deployment %q", deploymentName)
podLabels := map[string]string{"name": nginxImageName}
d := framework.NewDeployment(deploymentName, int32(0), podLabels, nginxImageName, nginxImage, extensions.RollingUpdateDeploymentStrategyType)
deployment, err := c.Extensions().Deployments(ns).Create(d)
Expect(err).NotTo(HaveOccurred())
err = framework.WaitForDeploymentRevisionAndImage(c, ns, deploymentName, "1", nginxImage)
Expect(err).NotTo(HaveOccurred())
// TODO: Switch this to do a non-cascading deletion of the Deployment, mutate the ReplicaSet
// once it has no owner reference, then recreate the Deployment if we ever proceed with
// https://github.com/kubernetes/kubernetes/issues/44237
framework.Logf("Mock a hash collision")
newRS, err := deploymentutil.GetNewReplicaSet(deployment, c)
Expect(err).NotTo(HaveOccurred())
var nilRs *extensions.ReplicaSet
Expect(newRS).NotTo(Equal(nilRs))
_, err = framework.UpdateReplicaSetWithRetries(c, ns, newRS.Name, func(update *extensions.ReplicaSet) {
*update.Spec.Template.Spec.TerminationGracePeriodSeconds = int64(5)
})
Expect(err).NotTo(HaveOccurred())
framework.Logf("Expect deployment collision counter to increment")
if err := wait.PollImmediate(time.Second, time.Minute, func() (bool, error) {
d, err := c.Extensions().Deployments(ns).Get(deploymentName, metav1.GetOptions{})
if err != nil {
framework.Logf("cannot get deployment %q: %v", deploymentName, err)
return false, nil
}
framework.Logf(spew.Sprintf("deployment status: %#v", d.Status))
return d.Status.CollisionCount != nil && *d.Status.CollisionCount == int64(1), nil
}); err != nil {
framework.Failf("Failed to increment collision counter for deployment %q: %v", deploymentName, err)
}
framework.Logf("Expect a new ReplicaSet to be created")
err = framework.WaitForDeploymentRevisionAndImage(c, ns, deploymentName, "2", nginxImage)
Expect(err).NotTo(HaveOccurred())
}
...@@ -3348,9 +3348,10 @@ func WatchRecreateDeployment(c clientset.Interface, d *extensions.Deployment) er ...@@ -3348,9 +3348,10 @@ func WatchRecreateDeployment(c clientset.Interface, d *extensions.Deployment) er
} }
// WaitForDeploymentRevisionAndImage waits for the deployment's and its new RS's revision and container image to match the given revision and image. // WaitForDeploymentRevisionAndImage waits for the deployment's and its new RS's revision and container image to match the given revision and image.
// Note that deployment revision and its new RS revision should be updated shortly, so we only wait for 1 minute here to fail early. // Note that deployment revision and its new RS revision should be updated shortly most of the time, but an overwhelmed RS controller
// may result in taking longer to relabel a RS.
func WaitForDeploymentRevisionAndImage(c clientset.Interface, ns, deploymentName string, revision, image string) error { func WaitForDeploymentRevisionAndImage(c clientset.Interface, ns, deploymentName string, revision, image string) error {
return testutil.WaitForDeploymentRevisionAndImage(c, ns, deploymentName, revision, image, Logf, Poll, pollShortTimeout) return testutil.WaitForDeploymentRevisionAndImage(c, ns, deploymentName, revision, image, Logf, Poll, pollLongTimeout)
} }
// CheckNewRSAnnotations check if the new RS's annotation is as expected // CheckNewRSAnnotations check if the new RS's annotation is as expected
...@@ -3486,16 +3487,17 @@ func WaitForPartialEvents(c clientset.Interface, ns string, objOrRef runtime.Obj ...@@ -3486,16 +3487,17 @@ func WaitForPartialEvents(c clientset.Interface, ns string, objOrRef runtime.Obj
type updateDeploymentFunc func(d *extensions.Deployment) type updateDeploymentFunc func(d *extensions.Deployment)
func UpdateDeploymentWithRetries(c clientset.Interface, namespace, name string, applyUpdate updateDeploymentFunc) (deployment *extensions.Deployment, err error) { func UpdateDeploymentWithRetries(c clientset.Interface, namespace, name string, applyUpdate updateDeploymentFunc) (*extensions.Deployment, error) {
deployments := c.Extensions().Deployments(namespace) var deployment *extensions.Deployment
var updateErr error var updateErr error
pollErr := wait.Poll(10*time.Millisecond, 1*time.Minute, func() (bool, error) { pollErr := wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
if deployment, err = deployments.Get(name, metav1.GetOptions{}); err != nil { var err error
if deployment, err = c.Extensions().Deployments(namespace).Get(name, metav1.GetOptions{}); err != nil {
return false, err return false, err
} }
// Apply the update, then attempt to push it to the apiserver. // Apply the update, then attempt to push it to the apiserver.
applyUpdate(deployment) applyUpdate(deployment)
if deployment, err = deployments.Update(deployment); err == nil { if deployment, err = c.Extensions().Deployments(namespace).Update(deployment); err == nil {
Logf("Updating deployment %s", name) Logf("Updating deployment %s", name)
return true, nil return true, nil
} }
...@@ -3513,7 +3515,7 @@ type updateRsFunc func(d *extensions.ReplicaSet) ...@@ -3513,7 +3515,7 @@ type updateRsFunc func(d *extensions.ReplicaSet)
func UpdateReplicaSetWithRetries(c clientset.Interface, namespace, name string, applyUpdate updateRsFunc) (*extensions.ReplicaSet, error) { func UpdateReplicaSetWithRetries(c clientset.Interface, namespace, name string, applyUpdate updateRsFunc) (*extensions.ReplicaSet, error) {
var rs *extensions.ReplicaSet var rs *extensions.ReplicaSet
var updateErr error var updateErr error
pollErr := wait.PollImmediate(10*time.Millisecond, 1*time.Minute, func() (bool, error) { pollErr := wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
var err error var err error
if rs, err = c.Extensions().ReplicaSets(namespace).Get(name, metav1.GetOptions{}); err != nil { if rs, err = c.Extensions().ReplicaSets(namespace).Get(name, metav1.GetOptions{}); err != nil {
return false, err return false, err
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment