Make Service.UpdateStatus non-ambiguous#2804
Conversation
| } | ||
| } | ||
|
|
||
| func (u *Updater) annotationsUpdated(service *api.Service) bool { |
There was a problem hiding this comment.
This was my naive way to double-check that no tasks had to be updated; I couldn't find a canonical way to determine if it's a spec-only change, or if tasks (containers) had to be updated; perhaps there is somewhere
There was a problem hiding this comment.
what's the problem with trusting the dirtySlots check? (keeping in mind that I haven't expanded that part of the code yet)
There was a problem hiding this comment.
IIUC;
- The
dirtySlotscheck checks if any of the containers (tasks) have to be updated, so that the reconciliation loop has to check for that to finish - If
len(dirtySlots) == 0, no containers have to be updated
At that point, there's three possibilities;
service.UpdateStatus == updating or rollback_started- this means a reconciliation loop was started and has now finished (socompleteUpdate)service.UpdateStatus == nil, but nothing changed (annotationsUpdated == false); apparently there was nothing to update; don't update theService.UpdateStatus, because nothing happenedservice.UpdateStatus == niland annotations changed; this means we actually updated something, and are now done; runcompleteUpdateto set theService.UpdateStatus
Perhaps we don't have to take 2. into account, and always call completeUpdate update the UpdateStatus once we get at this point; I wasn't sure if there's any other detection before this to cancel the update earlier (if nothing changed); also not sure if running completeUpdate in the "nothing changed" situation would have side-effects
There was a problem hiding this comment.
I think the DeepEqual is okay. When comparing a task spec to a service spec, there is some subtlety - see IsTaskDirty.
Are annotations the only things that can change without causing tasks to become dirty? I would have thought there were other cases, but can't think of any examples offhand. It might make sense to call this something like serviceSpecChanged just to be defensive.
|
ping @dperny @aaronlehmann PTAL - this seems to work, but perhaps there's a reason for this being implemented this way |
| case service.UpdateStatus == nil && force: | ||
| // Force marking the status as updated; to account for annotation-only updates. | ||
| service.UpdateStatus = &api.UpdateStatus{ | ||
| StartedAt: ptypes.MustTimestampProto(time.Now()), |
There was a problem hiding this comment.
Not sure if this was really needed (setting StartedAt), but thought it would be "ok" for consistency. Happy to remove though
In situations where only annotations of a service are updated, SwarmKit never marks a service as `UpdateStateUpdating`; the service's `UpdateStatus` is set to `nil`, and never updated after. Because of this, it's not possible to verify if an update actually happened / reconciled, unless resorting to hacky solutions, such as comparing the services `Version` before and after. Even those hacky solutions are not useful, because this requires knowledge about _which_ conditions require tasks to be updated, and which conditions not ( and require `UpdateStatus` to be checked). Such knowledge should be internal to SwarmKit, and not needed for users of the API. This patch modifies the behavior code to try to make this situation non-ambigious, by marking services as "updated" in all cases where the service has reconciled. Note that this patch causes an extra update to be performed (to write the service's `UpdateStatus` to the store). If this is a concern, we could possibly modify `controlapi.UpdateService()` to write the `UpdateStatus` immediately, instead of setting it to `nil`. Signed-off-by: Sebastiaan van Stijn <[email protected]>
1572a5e to
171d814
Compare
I don't remember if there's a good reason for this. Unless it's like this for a good reason, temporarily setting |
|
Okay, it took me a few minutes to regain the context. I believe it's like this by design. If no tasks need to be updated, then technically no update is taking place even though the spec changed. Thus I can see the consistency argument for always providing an |
| } | ||
| } | ||
|
|
||
| func (u *Updater) annotationsUpdated(service *api.Service) bool { |
There was a problem hiding this comment.
I think the DeepEqual is okay. When comparing a task spec to a service spec, there is some subtlety - see IsTaskDirty.
Are annotations the only things that can change without causing tasks to become dirty? I would have thought there were other cases, but can't think of any examples offhand. It might make sense to call this something like serviceSpecChanged just to be defensive.
| service.UpdateStatus = &api.UpdateStatus{ | ||
| StartedAt: ptypes.MustTimestampProto(time.Now()), | ||
| State: api.UpdateStatus_COMPLETED, | ||
| Message: "update completed", |
There was a problem hiding this comment.
Maybe mention in the message that no tasks needed to be updated?
|
LGTM. |
Reverts the change to swarmkit that made all updates set UpdateStatus to Completed Signed-off-by: Drew Erny <[email protected]>
Reverts the change to swarmkit that made all updates set UpdateStatus to Completed Signed-off-by: Drew Erny <[email protected]> (cherry picked from commit c7d9599) Signed-off-by: Sebastiaan van Stijn <[email protected]>
[19.03 backport] Revert moby/swarmkit#2804
Reverts the change to swarmkit that made all updates set UpdateStatus to Completed Signed-off-by: Drew Erny <[email protected]> (cherry picked from commit c7d9599e3d95ce588113dc351facb2befac062fa) Signed-off-by: Sebastiaan van Stijn <[email protected]> Upstream-commit: d0f4f42bd4646f1741acd0fa22699bf1ac553c03 Component: engine
[19.03 backport] Revert moby/swarmkit#2804 Upstream-commit: 0678d71038ff7a253e67392675485309b971ecb8 Component: engine
Reverts the change to swarmkit that made all updates set UpdateStatus to Completed Signed-off-by: Drew Erny <[email protected]> Upstream-commit: c7d9599e3d95ce588113dc351facb2befac062fa Component: engine
Revert moby/swarmkit#2804 Upstream-commit: 54043d2f6f60e95a341e42257c4c80f86a89af6e Component: engine
Reverts the change to swarmkit that made all updates set UpdateStatus to Completed Signed-off-by: Drew Erny <[email protected]> Signed-off-by: zach <[email protected]>
See moby/moby#38520 for some background on this change
In situations where only annotations of a service are updated, SwarmKit never
marks a service as
UpdateStateUpdating; the service'sUpdateStatusis setto
nil, and never updated after.Because of this, it's not possible to verify if an update actually happened /
reconciled, unless resorting to hacky solutions, such as comparing the services
Versionbefore and after.Even those hacky solutions are not useful, because this requires knowledge
about which conditions require tasks to be updated, and which conditions not (
and require
UpdateStatusto be checked). Such knowledge should be internal toSwarmKit, and not needed for users of the API.
This patch modifies the behavior code to try to make this situation
non-ambigious, by marking services as "updated" in all cases where the service
has reconciled.
Note that this patch causes an extra update to be performed (to write the
service's
UpdateStatusto the store). If this is a concern, we could possiblymodify
controlapi.UpdateService()to write theUpdateStatusimmediately,instead of setting it to
nil.