Skip to content

Make Service.UpdateStatus non-ambiguous#2804

Merged
dperny merged 1 commit intomoby:masterfrom
thaJeztah:make_update_status_non_ambiguous
Jan 15, 2019
Merged

Make Service.UpdateStatus non-ambiguous#2804
dperny merged 1 commit intomoby:masterfrom
thaJeztah:make_update_status_non_ambiguous

Conversation

@thaJeztah
Copy link
Member

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'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.

}
}

func (u *Updater) annotationsUpdated(service *api.Service) bool {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the problem with trusting the dirtySlots check? (keeping in mind that I haven't expanded that part of the code yet)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC;

  • The dirtySlots check 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;

  1. service.UpdateStatus == updating or rollback_started - this means a reconciliation loop was started and has now finished (so completeUpdate)
  2. service.UpdateStatus == nil, but nothing changed (annotationsUpdated == false); apparently there was nothing to update; don't update the Service.UpdateStatus, because nothing happened
  3. service.UpdateStatus == nil and annotations changed; this means we actually updated something, and are now done; run completeUpdate to set the Service.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

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@thaJeztah
Copy link
Member Author

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()),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this was really needed (setting StartedAt), but thought it would be "ok" for consistency. Happy to remove though

@thaJeztah thaJeztah changed the title Make Service.UpdateStatus non-ambigious Make Service.UpdateStatus non-ambiguous Jan 10, 2019
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]>
@thaJeztah thaJeztah force-pushed the make_update_status_non_ambiguous branch from 1572a5e to 171d814 Compare January 10, 2019 16:42
@aaronlehmann
Copy link
Collaborator

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.

I don't remember if there's a good reason for this. Unless it's like this for a good reason, temporarily setting UpdateStartUpdating on an annotation-only update might be a simpler solution and more consistent with other kinds of updates.

@aaronlehmann
Copy link
Collaborator

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 UpdateStatus is never populated.

I can see the consistency argument for always providing an UpdateStatus after making a chance to a service. I can't think of a practical downside (but don't take my word for it). The PR looks fine overall as far as I can tell.

}
}

func (u *Updater) annotationsUpdated(service *api.Service) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe mention in the message that no tasks needed to be updated?

@dperny
Copy link
Collaborator

dperny commented Jan 15, 2019

LGTM.

@dperny dperny merged commit 47b1cd4 into moby:master Jan 15, 2019
@thaJeztah thaJeztah deleted the make_update_status_non_ambiguous branch April 10, 2019 12:51
dperny added a commit to dperny/docker that referenced this pull request May 29, 2019
Reverts the change to swarmkit that made all updates set UpdateStatus to
Completed

Signed-off-by: Drew Erny <[email protected]>
thaJeztah pushed a commit to thaJeztah/docker that referenced this pull request Jun 3, 2019
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]>
tiborvass added a commit to moby/moby that referenced this pull request Jun 4, 2019
andrewhsu added a commit to docker-archive/engine that referenced this pull request Jun 4, 2019
docker-jenkins pushed a commit to docker-archive/docker-ce that referenced this pull request Jun 4, 2019
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
docker-jenkins pushed a commit to docker-archive/docker-ce that referenced this pull request Jun 4, 2019
[19.03 backport] Revert moby/swarmkit#2804
Upstream-commit: 0678d71038ff7a253e67392675485309b971ecb8
Component: engine
docker-jenkins pushed a commit to docker-archive/docker-ce that referenced this pull request Jun 4, 2019
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
docker-jenkins pushed a commit to docker-archive/docker-ce that referenced this pull request Jun 4, 2019
Revert moby/swarmkit#2804
Upstream-commit: 54043d2f6f60e95a341e42257c4c80f86a89af6e
Component: engine
burnMyDread pushed a commit to burnMyDread/moby that referenced this pull request Oct 21, 2019
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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants