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

Add support for the subuser calls in the rgw admin interface #644

Merged
merged 6 commits into from
Mar 17, 2022

Conversation

sebastianriese
Copy link
Contributor

@sebastianriese sebastianriese commented Feb 11, 2022

These commits add support for the subuser calls in the rgw admin interface.

Closes #521.

Implementing the subuser commands required a restructuring of the way the objects are serialized to API parameters. The way this was done is up to review and I am open to changes.

This is a breaking change, since the User type changes (by adding detailed type information for the fields related to subusers to support type safe parsing from the json responses). The API calls on the wire may change as well (as go-ceph now only serializes those parameters that are actually supported by the Ceph RGW Adminops API, not all parameters that are set in the "mirror" object on the go-ceph side).

See also the related discussion: #641.

Checklist

  • Added tests for features and functional changes
  • Public functions and types are documented
  • Standard formatting is applied to Go code
  • Is this a new API? Is this new API marked PREVIEW?

@sebastianriese sebastianriese marked this pull request as draft February 11, 2022 13:54
@sebastianriese sebastianriese changed the title Add support for the subuser calls in the rgw admin interface Draft: Add support for the subuser calls in the rgw admin interface Feb 11, 2022
@sebastianriese
Copy link
Contributor Author

One problem that I already spotted with my approach is, that the documentation does not seem to be complete with respect to the supported query parameters, e.g. the feature from #600 (getting users by access key), is not documented in the api docs: https://docs.ceph.com/en/latest/radosgw/adminops/#get-user-info, there only the uid parameter is specified (and marked required).

@ansiwen ansiwen added the API This PR includes a change to the public API of a go-ceph package label Feb 15, 2022
// NOTE: we use linear search here, as none of the API endpoints
// supports more than 10 parameters, in this case asymptotics don't
// matter and we are likely faster this way (even when compared to a
// map).
Copy link
Collaborator

Choose a reason for hiding this comment

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

Great comment, BTW.

@phlogistonjohn
Copy link
Collaborator

I'd like to know more about what you think could cause backwards incompatibility issues. The go-ceph library is v0 and we don't guarantee no breaking changes but we do try to avoid them as much as possible as the library is used in various codebases.

Personally, nothing just jumped out at me as having a breaking API change but I may have overlooked something.

I'll also tag @leseb who helps maintain the rgw admin part of go-ceph and is more knoledgeable about rgw admin than I am.

@sebastianriese
Copy link
Contributor Author

sebastianriese commented Feb 22, 2022

The potential problem I see, is that I restrict the parameters that are serialized and passed to the API. Although I do so based on the official documentation of the API, this means that there could be code out there, that passed in more parameters before the change and those parameters did something though they were not specified – I know the API documentation isn't fully reliable. This in turn would break real use cases.

I know of one example where I don't allow a parameter that isn't specified in the API documentation, but passing it does actually work when it's included in the API call, namely access-key in the GetUser call (compare #600). Given that I know this, I can fix it easily, the trouble is the undocumented parameters I don't know about.

Nevertheless, if this potential breakage is acceptable to you, it feels safer to me, to only send selected parameters the API (in the sense of "be conservative in what you send").
It would certainly be an option to note it in the change note, and have people complain if their real-world requests no longer work.

(The change will, of course, also break code that accessed the swift-related parts of the User structure – so far typed []interface{} – in any way).

I'll have a look at the RGW source code, perhaps the supported parameter sets can be extracted from there.

@sebastianriese
Copy link
Contributor Author

sebastianriese commented Feb 22, 2022

Okay, that looks like the right place: https://github.com/ceph/ceph/blob/193895ffba4245787a2f50bbd5b80132f0e76e74/src/rgw/rgw_rest_user.cc#L72

I guess we can take the supported parameters from there. Then we can be sure that we don't break code, because any other parameters someone might send, will just be ignored by rgw.

@sebastianriese
Copy link
Contributor Author

sebastianriese commented Feb 23, 2022

I have now updated the lists based on determining the supported parameters from the ceph source code and I have documented parameters supported by RGW that we do not yet support (as we don't have a field to specify them in our structs). This should make the change safe, in the sense that code using this library do to an API call will have the same effect before and after this change (although the API call on the wire will potentially change, as fields ignored by the RGW Adminops API will not be serialized).

In the process I've noted a few irregularities in the typing of the API parameters in this code base (but I guess that is not for this PR to address). E.g. int us used for parameters that are parsed as uint32_t or int32_t on the RGW side and at least in one case int is used as the type for a boolean flag (it works out as rgw allows to representations of booleans in the parameters: 0|1 and false|true). I've opened an issue to track that problem: #656.

@sebastianriese
Copy link
Contributor Author

I've marked the new API methods as PREVIEW (as the development documentation advises).

Should the new types also be marked PREVIEW in some way, or are they not covered by the API stability tracking?

@phlogistonjohn
Copy link
Collaborator

I've marked the new API methods as PREVIEW (as the development documentation advises).

Great thanks.

Should the new types also be marked PREVIEW in some way, or are they not covered by the API stability tracking?

Types currently do not need to be marked PREVIEW. As you surmised they're not (directly) part of the API tracking.

We maintainers are currently discussing the possibility of dropping "PREVIEW" in the doc comment and relying entirely on the "ceph_preview" build tag. Aside from the annoyance of having to deal with another process change, we think this would be simpler to document and ask contributors to implement. However, the tooling will need to be updated to match.

@sebastianriese sebastianriese force-pushed the feature/rgw-admin-subuser branch 3 times, most recently from 30a24e0 to 4eae29b Compare February 28, 2022 19:06
@sebastianriese
Copy link
Contributor Author

I've now improved the validation of API parameters (and corresponding errors) and expanded the tests.

Additionally, I've added some comments to the source that explain some irregularities in the RGW Admin OPS API (and how this impacts the API library/the choices made in the code because of this).

The tests could be expanded and have tighter matchers in places, but I'll un-draft this now, as I think it is mostly ready and those short-comings can be fixed together with any issues raised in further review.

@sebastianriese sebastianriese changed the title Draft: Add support for the subuser calls in the rgw admin interface Add support for the subuser calls in the rgw admin interface Feb 28, 2022
@sebastianriese sebastianriese marked this pull request as ready for review March 1, 2022 10:46
@@ -132,7 +134,7 @@ func (api *API) GetBucketPolicy(ctx context.Context, bucket Bucket) (Policy, err

// RemoveBucket will remove a given token from the object store
func (api *API) RemoveBucket(ctx context.Context, bucket Bucket) error {
_, err := api.call(ctx, http.MethodDelete, "/bucket", valueToURLParams(bucket))
_, err := api.call(ctx, http.MethodDelete, "/bucket", valueToURLParams(bucket, []string{"bucket", "purge-objects"}))
Copy link
Member

Choose a reason for hiding this comment

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

Is this purging all the objects from the bucket? If so, isn't that dangerous? Would it be good to have validation or something passed to the API by the user to do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did not touch change the behaviour of this API call. I only added the filtering in valueToURLParams (so only those parameters that are actually supported by the API according to the ceph-rgw source code are serialized to the query string).

It is certainly a dangerous operation (even without purge objects, given that all obejcts that are only in this bucket will be deleted independently of the purge-objects setting), but the way it behaves does not change with this commit.

With purge-objects set to true all the objects in the bucket will be deleted, before deleting the bucket (I guess that means they will also be deleted from other buckets that may contain them).

For purge-objects to happen *bucket.PurgeObjects must be set to true, this will never be the case for Bucket objects returned from the API, so explicit action is necessary on the side of the user.

@@ -50,7 +50,8 @@ type Usage struct {

// GetUsage request bandwidth usage information on the object store
func (api *API) GetUsage(ctx context.Context, usage Usage) (Usage, error) {
body, err := api.call(ctx, http.MethodGet, "/usage", valueToURLParams(usage))
// unsupported parameters: category, bucket
Copy link
Member

Choose a reason for hiding this comment

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

Can we clarify? Unsupported by this API or by the RGW admin ops API?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've clarified to // valid parameters not supported by go-ceph

If someone will implement support for the currently unsupported parameters in the structs, the parameter in question will also have to be added to the whitelists in the corresponding methods.

@@ -65,6 +66,7 @@ func (api *API) GetUsage(ctx context.Context, usage Usage) (Usage, error) {

// TrimUsage removes bandwidth usage information. With no dates specified, removes all usage information.
func (api *API) TrimUsage(ctx context.Context, usage Usage) error {
_, err := api.call(ctx, http.MethodDelete, "/usage", valueToURLParams(usage))
// unsupported parameters: bucket
Copy link
Member

Choose a reason for hiding this comment

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

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All the comments have been updated.

@mergify
Copy link

mergify bot commented Mar 14, 2022

This pull request now has conflicts with the target branch. Could you please resolve conflicts and force push the corrected changes? 🙏

The following changes have been done:

* Up until now everything in the argument objects was serialized to
  the API calls. This was updated to restrict the serialization to
  the API call parameters that are parsed in the Ceph RGW source code.

  Parameters not yet supported by us are documented as comments.
  Note, that a superset of the documented parameters is supported.

  Documentation for the API:
  <https://docs.ceph.com/en/pacific/radosgw/adminops/>

  Link to the used source tree:
  <https://github.com/ceph/ceph/tree/193895ffba4245787a2f50bbd5b80132f0e76e74/src/rgw>

  The argument parsing happens in the rgw_rest_*.cc files.

* The serialization code (valueToURLParams) has been updated to
  be more in line with other serialization methods:

  - A tag "-" causes the field to be ignored
  - Only the first item in a list of tag items is interpreted as
    name.
  - The handling of pointer and direct data types has been
    harmonized (the same rules for the names and value apply now).

* There is still room for improvement to make things more consistent:
  A pointer to a non-elementary data type will emit unexpected
  request parameters.

* Presence of required parameters is not validated by the library,
  this is left to the API.

Signed-off-by: Sebastian Riese <[email protected]>
Only one of the two code paths of buildQueryPath was tested so far.
This makes the test harness tight by testing the second one (where
the path already contains a query parameter).

Signed-off-by: Sebastian Riese <[email protected]>
THIS POTENTIALLY BREAKY DOWNSTREAM CODE (as it changes the types
of exported fields in an existing, exported struct).

The fields of the User structure representing the Subuser information
have been specified to parse this data strictly and typesafe.

The fields SwiftKeys and Subusers need the url:"-" annotation,
because otherwise url-keys in that substructure would clash with
those in the User structure.

Signed-off-by: Sebastian Riese <[email protected]>
@sebastianriese
Copy link
Contributor Author

Rebased to the newest master.

leseb
leseb previously approved these changes Mar 17, 2022
@mergify mergify bot dismissed leseb’s stale review March 17, 2022 09:41

Pull request has been modified.

leseb
leseb previously approved these changes Mar 17, 2022
@sebastianriese
Copy link
Contributor Author

Thanks for the reviews. I've slightly squashed the history and did some minor improvements to the tests – from my side it is ready to merge now.

Copy link
Collaborator

@phlogistonjohn phlogistonjohn left a comment

Choose a reason for hiding this comment

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

Hi there! Thanks a lot for working with @leseb on the functionality. Now that is squared away I do notice a few small book keeping related issues that need to be resolved.
I'm aware that these can be kind of annoying. I do wish I had noticed the file/ceph_preview build flag issue sooner, but I hope you wont find that too difficult to resolve.

}

// CreateSubuser - https://docs.ceph.com/en/latest/radosgw/adminops/#create-subuser
// PREVIEW
Copy link
Collaborator

Choose a reason for hiding this comment

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

New functions that are in preview state must be located in files marked with the "ceph_preview" build tag. I thought the CI would have caught this but I guess not, sorry. I suggest moving the net new functions to "subuser.go"

Copy link
Collaborator

Choose a reason for hiding this comment

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

Let me know if you have any questions about this process.

{
"name": "API.CreateSubuser",
"comment": "CreateSubuser - https://docs.ceph.com/en/latest/radosgw/adminops/#create-subuser\n PREVIEW\n",
"added_in_version": "v0.14.0",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Release v0.14 is already out. The added_in_version and expected_stable_version need to be incremented. You can do it by hand or by deleting the new entries and re-running the make api-update commands.
We are aware that this is annoying and time consuming and are looking into ways to avoid putting the burden on contributors... but we don't have a solution yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I tried to fix this manually, but obviously didn't catch all occurrences – I'll use the tools to regenerate it properly.

{
"name": "API.RemoveSubuser",
"comment": "RemoveSubuser - https://docs.ceph.com/en/latest/radosgw/adminops/#remove-subuser\n PREVIEW\n",
"added_in_version": "v0.14.0",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same.

{
"name": "API.ModifySubuser",
"comment": "ModifySubuser - https://docs.ceph.com/en/latest/radosgw/adminops/#modify-subuser\n PREVIEW\n",
"added_in_version": "v0.14.0",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same

@@ -8,57 +8,59 @@

### Deprecated APIs

Name | Deprecated in Version | Expected Removal Version |
Copy link
Collaborator

Choose a reason for hiding this comment

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

I suggest regenerating this file too.

Some unit tests for the validation and integration tests.

Signed-off-by: Sebastian Riese <[email protected]>
@mergify mergify bot dismissed leseb’s stale review March 17, 2022 15:53

Pull request has been modified.

@sebastianriese
Copy link
Contributor Author

@phlogistonjohn The issues you raised should be fixed now. Thanks again for guiding me through the process!

Copy link
Collaborator

@phlogistonjohn phlogistonjohn left a comment

Choose a reason for hiding this comment

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

LGTM, thanks a bunch for working on this!

@mergify mergify bot merged commit 6a4d7eb into ceph:master Mar 17, 2022
@sebastianriese sebastianriese mentioned this pull request Mar 22, 2022
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API This PR includes a change to the public API of a go-ceph package
Projects
None yet
Development

Successfully merging this pull request may close these issues.

create subuser in rgw
4 participants