Skip to content
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

Use implicit field mask paths in IS #249

Merged
merged 4 commits into from
Mar 8, 2019

Conversation

htdvisser
Copy link
Contributor

Summary:

Since #69 (specifically the decisions in #69 (comment) and related meeting) we now allow empty field masks. This PR makes sure that the Identity Server handles such requests accordingly.

Changes:

  • Field Mask paths on IS requests are "cleaned" according to a set of possible/allowed fields, as well as fields to add (default fields on Get-like requests) or remove (ignored fields on Set-like requests)
  • CLI is updated to no longer implicitly select the "name" field.

Notes for Reviewers:

@rvolosatovs if you think it could be useful in other places (end device registries), we can move the cleanFieldMaskPaths utility to ttnpb.

Release Notes: (optional)

The Identity Server now treats empty field masks as if ids and created/updated times were requested.

@htdvisser htdvisser added c/identity server This is related to the Identity Server ui/cli This is related to ttn-lw-cli labels Mar 6, 2019
@htdvisser htdvisser added this to the March 2019 milestone Mar 6, 2019
@htdvisser htdvisser self-assigned this Mar 6, 2019
@htdvisser htdvisser requested a review from rvolosatovs March 6, 2019 14:53
@htdvisser
Copy link
Contributor Author

Setting prio/high as this is required for 3.0.0

Copy link
Contributor

@rvolosatovs rvolosatovs left a comment

Choose a reason for hiding this comment

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

Not explicitly requesting changes/approving, since I don't understand what's going on

if len(req.FieldMask.Paths) == 0 {
req.FieldMask.Paths = updatePaths
}
if ttnpb.HasAnyField(req.FieldMask.Paths, "contact_info") {
Copy link
Contributor

Choose a reason for hiding this comment

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

This will not evaluate to true if any of the child paths in contact_info, e.g. contact_info.contact_type is set(https://github.com/TheThingsNetwork/lorawan-stack/blob/master/api/contact_info.proto#L45)
Is that expected behavior?
Additionally, it seems like contact_info is not part of allowed fieldmasks of any PRC at https://github.com/TheThingsNetwork/lorawan-stack/blob/9e35fc3e7bf1ce817076ed39a916914e1b739de7/pkg/ttnpb/field_mask_validation.go at all.
How is this supposed to work?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. contact_info is a slice. Field mask paths don't recurse into slices.
  2. EndDevice doesn't have a contact_info field. For applications and other entities, the allowed paths come from ttnpb.ApplicationFieldPathsNested etc.

@@ -83,6 +83,7 @@ func (is *IdentityServer) getApplication(ctx context.Context, req *ttnpb.GetAppl
if err = is.RequireAuthenticated(ctx); err != nil {
return nil, err
}
req.FieldMask.Paths = cleanFieldMaskPaths(ttnpb.ApplicationFieldPathsNested, req.FieldMask.Paths, getPaths, nil)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this necessary?
Why not just set this to getPaths if len(req.FieldMask.Paths) == 0?
Basically the same question for all other invocations - I really don't get what's going on here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

getPaths contains the fields that are implicitly part of the field mask, so they are always added to the field mask in the request, if it doesn't already contain them.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, but there's no harm in adding a field twice - you can just append the fields - we do the same in JS/NS and AS AFAIK.

Copy link
Contributor

Choose a reason for hiding this comment

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

In order to construct the slice of required fields, Set registry endpoint in NS constructs a gets and sets:

gets := append(req.FieldMask.Paths[:0:0], req.FieldMask.Paths...)
if ttnpb.HasAnyField(req.FieldMask.Paths, "mac_state.device_class") {
gets = append(gets,
"mac_state.current_parameters",
"mac_state.desired_parameters",
"queued_application_downlinks",
)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not the NS/JS. In the IS we prefer to have paths in the field mask only once.

Copy link
Contributor

Choose a reason for hiding this comment

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

But then why not ttnpb.EnsureFieldpaths(paths []string, ensure ...string) []string?
You pass the existing fieldmask and the paths you want to add if missing.
You don't need 4 arguments for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is no ttnpb.EnsureFieldPaths, I want to combine this with the allowed paths, I want to be able to specify paths that need to be deleted if present, and finally, I want to do it in a single pass instead of combining EnsureFieldPaths, EnsureNotFieldPaths, IntersectFieldPaths, UniqueFieldPaths.

Copy link
Contributor

Choose a reason for hiding this comment

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

  1. We have API layer middleware, which should validate that fields that should not be present are not present.
  2. Invalid fieldpaths, which still could get through should be validated explicitly and if present - throw an error.

RPC implementation simply should not delete anything passed to it. Cleaning and validation belongs to the API layer middleware. RPC should simply upsert the required fields.

@htdvisser htdvisser requested a review from johanstokking March 8, 2019 10:15
@htdvisser htdvisser added blocking release This is blocking a release and removed prio/high labels Mar 8, 2019
@htdvisser htdvisser merged commit 68e50c3 into master Mar 8, 2019
@htdvisser htdvisser deleted the feature/69-implicit-field-mask-paths branch March 8, 2019 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocking release This is blocking a release c/identity server This is related to the Identity Server ui/cli This is related to ttn-lw-cli
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants