api: Centralize defaults and add InsertDefaults flag#1744
api: Centralize defaults and add InsertDefaults flag#1744aaronlehmann merged 1 commit intomoby:masterfrom
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1744 +/- ##
==========================================
+ Coverage 54.33% 54.35% +0.01%
==========================================
Files 111 111
Lines 19323 19327 +4
==========================================
+ Hits 10499 10505 +6
+ Misses 7559 7557 -2
Partials 1265 1265Continue to review full report at Codecov.
|
manager/controlapi/service.go
Outdated
| return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID) | ||
| } | ||
|
|
||
| service.InterpolatedSpec = defaults.InterpolateService(&service.Spec) |
There was a problem hiding this comment.
add to ListServices as well
This is a decision to make. Inconsistency in different objects would cause confusion. Can we list the alternatives and what Docker has been using in other places? |
I only meant that I haven't gone through the effort of adding this to other objects because the design hasn't been finalized yet. I think it should be part of every object. |
|
Since swarmkit is part of Docker, if we are going to implement this, should objects in other Docker |
|
To the extent that other objects have |
4fd3c63 to
e5274d2
Compare
|
Rebased (fairly involved one, since so many things changed since this was opened - new deepcopy, native protobuf types, orchestrator changes, updater changes, etc.) Would love to get this going again |
| }, | ||
| Update: &api.UpdateConfig{ | ||
| FailureAction: api.UpdateConfig_PAUSE, | ||
| Monitor: gogotypes.DurationProto(5 * time.Second), |
There was a problem hiding this comment.
There are more parameters like parallelism, update-delay, etc.
There was a problem hiding this comment.
The default value of UpdateDelay is 0, so it's not necessary to include it here. You're right that Parallelism should be included. It used to default to 0, but now defaults to 1. Fixing.
api/objects.proto
Outdated
| // and it is useful for that to return detailed information about | ||
| // what values are actually being used to run the service. In the | ||
| // future, we should add add InterpolatedSpec to other objects as well. | ||
| ServiceSpec interpolated_spec = 7; |
There was a problem hiding this comment.
I have concern to add another ServiceSpec in service object. It might confuse developer which one to update.
There was a problem hiding this comment.
I'd welcome any other suggestions.
I actually wanted to support updating based on InterpolatedSpec as a feature. It would let the end user lock in the current default values.
There was a problem hiding this comment.
If it's only generated on the fly, it's ok.
There was a problem hiding this comment.
Expanded the comment to clarify.
There was a problem hiding this comment.
I agree with this design.
Do you think the user should be able to view both the service spec they provided, and the full spec on inspect? As a user, maybe I don't want to always see the defaults.
There was a problem hiding this comment.
This will be the behavior with docker inspect <servicename>, which just dumps the JSON. I think docker inspect --pretty <servicename> should show values from the interpolated spec.
e5274d2 to
c2a8bd3
Compare
|
LGTM |
c2a8bd3 to
1a4b9a1
Compare
I don't think the client should have to set all fields, from a usability perspective. It makes it harder to change defaults later for the user of the API, and for us to update protos. |
|
What bothers me is I don't recall ever seeing one API doing this. How is the world dealing wit h this right now? I'm sure we're not the first ones struggling with API defaults :) |
|
@aluzzardi: I'm not sure. This seems to be a problem that's specific to declarative APIs - otherwise the server can just fill in default values when it returns objects. k8s manages defaults in the apiserver - see kubernetes/enhancements#55 and the issue linked from there. I couldn't find any information about how apiserver defaults are exposed to end users. I don't think this is particularly complex. We basically have two choices: offer a version of the spec that has missing fields filled in with defaults ( |
I think it's generic to REST APIs - What I don't like is we're going to make the API response more complex with another thing to understand for API users. e.g. getting the interpolated spec and putting it back as the spec is bad. Also, what happens to the CLI - if we display both it's just going be a pain to get meaningful data back. |
The reason I think it's specific to declarative APIs is that in most other cases it's fine to fill in extra fields in the response. For example, if I
I understand your concerns but I'm wondering if you think there's a better way than what I'm proposing here. As I mentioned above, I see two basic approaches. We can either include something like BTW, I don't think getting the
I would suggest that Currently |
|
Discussed with @aluzzardi - let's change this so that instead of having The CLI can use the Consider clearing the |
1a4b9a1 to
bd68850
Compare
bd68850 to
dacc9da
Compare
|
Updated according to the above comment. PTAL. |
|
Rebased |
dacc9da to
de7eb77
Compare
manager/controlapi/service.go
Outdated
| service.Spec = *defaults.InterpolateService(&service.Spec) | ||
| // Clear version to prevent the returned service from being the | ||
| // basis for an update. | ||
| service.Meta.Version = api.Version{} |
There was a problem hiding this comment.
I'm having second thought about that.
It would make docker service inspect not include the version which is weird
There was a problem hiding this comment.
Okay, removed that part.
Currently, there is a problem with visibility of defaults. The best way to create a service is to only specify fields that you care about, because then the manager can apply appropriate defaults for the other fields. However, there's no way to know which values are actually being used for those fields. The spec is under the user's control, so if they don't specify a value (for example, `Spec.Task.Restart.Delay`), this field will show up as blank when the service is retrieved. We don't want to break the spec ownership model, but we do want a way to communicate actual values in use back to the client. For this, we add an `InsertDefaults` flag to the ControlAPI which allows fetching a version of the service with defaults inserted into empty fields. This also has the benefit of centralizing defaults. Default values for these fields that were defined in various places around the code are now centralized in `github.com/docker/swarmkit/api/defaults`. Right now this flag is only is only available for `Service`, but as we encounter situations where other objects have default values which need to be exposed, we should add this to other objects as well. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
de7eb77 to
27d3eb8
Compare
|
LGTM |
Currently, there is a problem with visibility of defaults. The best way
to create a service is to only specify fields that you care about,
because then the manager can apply appropriate defaults for the other
fields. However, there's no way to know which values are actually being
used for those fields. The spec is under the user's control, so if they
don't specify a value (for example,
Spec.Task.Restart.Delay), thisfield will show up as blank when the service is retrieved.
We don't want to break the spec ownership model, but we do want a way to
communicate actual values in use back to the client. For this, we add an
InsertDefaultsflag to the ControlAPI which allows fetching a versionof the service with defaults inserted into empty fields.
This also has the benefit of centralizing defaults. Default values for
these fields that were defined in various places around the code are now
centralized in
github.com/docker/swarmkit/api/defaults.Right now this flag is only is only available for
Service, but as weencounter situations where other objects have default values which need
to be exposed, we should add this to other objects as well.
cc @aluzzardi @stevvooe