-
Notifications
You must be signed in to change notification settings - Fork 38.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix kubectl stop rc with sequence numbers #9739
Conversation
Is sequenceNumber the right name? I assume this a pattern we'll use in the future for other reasons. |
@@ -47,14 +48,26 @@ func (rcStrategy) NamespaceScoped() bool { | |||
func (rcStrategy) PrepareForCreate(obj runtime.Object) { | |||
controller := obj.(*api.ReplicationController) | |||
controller.Status = api.ReplicationControllerStatus{} | |||
controller.Spec.SequenceNumber = 0 | |||
controller.Spec.SequenceNumber = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why twice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, i meant status
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arguably this should not be here at all; it looks like defaulting, so it should go in defaulting code, but 0 is the default for a number anyway so you don't really need to do anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, the intent here is to override the specification in rc.json, if any
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh-- gotcha. I think it's not important to do that though-- does it cause any harm if it starts out with seq 42?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why allow it? I think people might be tempted to update if we allow initialization (the only use case i can think of is cloning all the keys by getting and reputting to a diffferent apiserver). I'm fine defaulting the SequenceNumber to the answer to life the universe and everything, if that's what you meant :)
@smarterclayton Yeah, it's a general pattern. SequenceNumber is the most obvious name, but that doesn't mean there's not a better name possible :) I think the interesting debate to have about it is: |
The basic idea, of course, is to give you some idea about what version of the object is being used by the object's actuator, so that you can--in a generic way--tell when the system has quiesced. @bgrant0607 I've forgotten why we can't just have the actuator just reiterate the resourceVersion that it's acting on? Is this only because updates to status also increase the resourceVersion, or is there another reason, too? |
@@ -998,14 +998,16 @@ type ReplicationControllerSpec struct { | |||
// insufficient replicas are detected. Internally, this takes precedence over a | |||
// TemplateRef. | |||
// Must be set before converting to a v1beta1 or v1beta2 API object. | |||
Template *PodTemplateSpec `json:"template,omitempty"` | |||
Template *PodTemplateSpec `json:"template,omitempty"` | |||
SequenceNumber int `json:"sequenceNumber"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int64-- no ints in the API, they are variable-width.
GCE e2e build/test passed for commit 379916efde76ee47ffb825884aea63416dcc940f. |
// Any changes to the spec increment the sequence number, any changes to the | ||
// status reflect the sequence number of the corresponding spec | ||
if !reflect.DeepEqual(oldController.Spec, newController.Spec) { | ||
newController.Spec.SequenceNumber += 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
must be newController.Spec.SequenceNumber = oldController.Spec.SequenceNumber + 1
otherwise it's gameable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure that's easy enough to do, but so is the resource version right (this is the logic i've mostly applied when thinking about what to validate etc)? if someone tries to game it, all bets are off
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resourceVersion is generated by etcd & isn't gameable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean if someone doesn't re-get but just iterates through all the rvs
I agree it's different in that etcd will also reject if it's different
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a different kind of gaming. We can't ultimately stop a client that's determined to get it wrong. But we can ignore the seq # they pass in :)
And adding to my earlier list-- ...now that I think about it, endpoints should really be a subresource of services, or part of service.status. |
I can't think into the future enough to say it's safe to compare the resource version, even of a single resource, against itself. can we assume a future version of the same resource will have a higher resource version even if its from a different member/shard? The sequence number going up property is useful when a client wants to know the controller has seen an update, but doesn't care if it's seen many updates after that. |
|
Ah, yes, thank you-- I forgot about that part. We want to allow >=, not just ==. |
} | ||
|
||
// ReplicationControllerStatus represents the current status of a replication | ||
// controller. | ||
type ReplicationControllerStatus struct { | ||
// Replicas is the number of actual replicas. | ||
Replicas int `json:"replicas" description:"most recently oberved number of replicas"` | ||
Replicas int `json:"replicas" description:"most recently oberved number of replicas"` | ||
SequenceNumber int `json:"sequenceNumber" description:""` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing descriptions in swagger
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured people will change what i write anyway, so I'd just leave it blank till someone says: write this :)
PTAL, moved the Status.SequenceNumber code into the controller manager and added some more unittests |
GCE e2e build/test passed for commit cc767d3e32c4eb06f62d63eca2abe8a6157cdead. |
GCE e2e build/test passed for commit 915d36b0f848225ec6d8acde693e4b36f8a74bba. |
GCE e2e build/test passed for commit 7bb39e4a2a2fb3f703087850454d7f847c3266cf. |
for i, rc := 0, &controller; ; i++ { | ||
rc.Status.Replicas = numReplicas | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: extra blank line
I think this looks pretty good. I'd like to nail down whether sequenceNumber should go in metadata or in spec before we merge it, though. |
I haven't thought of a concrete reason to need two sequence numbers that couldn't be solved in spec directly (container sequence, for instance). If we add this to metadata we probably want to define it for objects which don't have clear specs (something like a user record, or an event). Also, probably need to clarify whether it applies to spec for things like nodes (answer is probably yes, but spec is a bit less clear for that type).
|
@@ -998,14 +998,16 @@ type ReplicationControllerSpec struct { | |||
// insufficient replicas are detected. Internally, this takes precedence over a | |||
// TemplateRef. | |||
// Must be set before converting to a v1beta1 or v1beta2 API object. | |||
Template *PodTemplateSpec `json:"template,omitempty"` | |||
Template *PodTemplateSpec `json:"template,omitempty"` | |||
SequenceNumber int64 `json:"sequenceNumber"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bprashanth mind adding a comment for this, since we are under api?
See also #7328 |
'Pologies for the delay, got sidetracked debugging an unrelated e2e failure to confirm it's not this change. Might still update some of the comments/descriptions but my latest set of commits has a Generation embedded in the object. PTAL. |
GCE e2e build/test passed for commit f75736f48e4553ccf218482756986b2bdd391252. |
52f559b
to
b69e033
Compare
GCE e2e build/test passed for commit 52f559bb6c7f9229746b1e7da871c2a3dd5a8dd7. |
GCE e2e build/test passed for commit b69e033a80d2c6462679a87e0673857426bbb667. |
GCE e2e build/test passed for commit 79760a54a00839cb3ae2bdd96c4473b487fed9a7. |
GCE e2e build/test passed for commit 66edecf930f16439ada47e29b9f32f62e1330024. |
@@ -1001,11 +1004,15 @@ type ReplicationControllerSpec struct { | |||
type ReplicationControllerStatus struct { | |||
// Replicas is the number of actual replicas. | |||
Replicas int `json:"replicas" description:"most recently oberved number of replicas"` | |||
|
|||
// ObservedGeneration is the most recent generation observed by the controller. | |||
ObservedGeneration int64 `json:"generation,omitempty" description:"reflects the generation of the most recently observed replication controller"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
json: observedGeneration
Looks pretty good. Just a couple minor comments. |
Please regenerate the swagger so that shippable can run. |
I did run update-swagger a few times (and the new commits ended up triggering k8s bot as well), I'll need to dig into why that doesn't seem to have worked |
PTAL, I'll figure out the swagger bug later, somehow verify followed by updated seems to have cleared some state and it worked. |
GCE e2e build/test passed for commit 1b31fc8b6c14151a231aab3872a95ffc8d2fd405. |
Shippable failure is a flake because n/w latencies are really high for some reason (took ~20s for a watch in my last run). Bumped up an integration test timeout that doesn't really need to be that short anyway with my last commit. |
GCE e2e build/test passed for commit 9ed9bd1. |
LGTM |
Fix kubectl stop rc with sequence numbers
Introduces the concept of sequence numbers for rcs fixing the behavior of kubectl stop rc in the process.
@lavalamp @bgrant0607 #9147
Still need to think of a good description string and look at why the conversion generating script doesn't autogenerate for rc.Spec changes (https://github.com/GoogleCloudPlatform/kubernetes/blob/master/pkg/api/v1/conversion.go#L30)