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

Added filter option to ipfs-cluster-ctl status #627

Merged
merged 16 commits into from Jan 8, 2019
Merged

Added filter option to ipfs-cluster-ctl status #627

merged 16 commits into from Jan 8, 2019

Conversation

kishansagathiya
Copy link
Contributor

When the --filter is passed, it will only fetch the peer information
where status of the pin matches with the filter value.
Valid filter values are tracker status types(i.e., "pinned",
"pin_error", "unpinning" etc), an alias of tracker status type (i.e.,
"queued" or "error"), comma separated list of tracker status type
and/or it aliases(i.e., "error,pinning")

On passing invalid filter value no status information will be shown

In particular, the filter would remove elements from []GlobalPinInfo
when none of the peers in GlobalPinInfo match the filter. If one peer
in the GlobalPinInfo matches the filter, the whole object is returned,
including the information for the other peers which may or not match it.

filter option works on statusAll("GET /pins"). For fetching pin status
for a CID("GET /pins/"), filter option would have no effect

Continueing from #478

Fixes #445

@kishansagathiya
Copy link
Contributor Author

kishansagathiya commented Dec 20, 2018

ipfs-cluster status --help print filter value instead of just filter

.// at end of the help message 
.
OPTIONS:
   --local         run operation only on the contacted peer
   --filter value  Comma seperated list of type tracker status and their aliases

Would you know why?

@@ -136,9 +136,13 @@ func (c *defaultClient) Status(ci cid.Cid, local bool) (api.GlobalPinInfo, error
}

// StatusAll gathers Status() for all tracked items.
func (c *defaultClient) StatusAll(local bool) ([]api.GlobalPinInfo, error) {
// If valid filter value is provided, it would fetch only those status information
// where status is matching the filter value
Copy link
Contributor

Choose a reason for hiding this comment

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

missing full stop

// If valid filter value is provided, it would fetch only those status information
// where status is matching the filter value
// Valid filter values are tracker status type, an alias of tracker status type
// (queued or error), comma separated list of track status type and/or it aliases
Copy link
Contributor

Choose a reason for hiding this comment

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

missing full stop

api/rest/client/methods_test.go Show resolved Hide resolved
api/rest/client/methods_test.go Show resolved Hide resolved
if local == "true" {
var pinInfos []types.PinInfoSerial

err := api.rpcClient.Call("",
Copy link
Contributor

Choose a reason for hiding this comment

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

While changing this function, can you update api.rpcClient.Call to api.rpcClient.CallContext and pass in the Request context r.Context().

Copy link
Contributor

Choose a reason for hiding this comment

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

Also can you fix the multilining of the function call so that params aren't on the same line as parens.

} else {
var pinInfos []types.GlobalPinInfoSerial
err := api.rpcClient.Call("",
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above.

tracker status type and/or it aliases ("error,pinning")
On passing invalid filter value no status information will be shown
List of tracker status types
https://github.com/ipfs/ipfs-cluster/blob/319c41cbf195b0453b8d1987991280d3121bac93/api/types.go#L66
Copy link
Contributor

Choose a reason for hiding this comment

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

No point using the commit url, as we will have to update this url every time we update the list. May as well just put all the filter values here and add a comment in api/types to remind people that if they add to the list of filters, they need to update this comment with the new values.

Copy link
Collaborator

Choose a reason for hiding this comment

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

You can loop and pretty print that list here. An invalid filter should throw an error (catching it both in the client (to avoid making a request for nothing) and in the server side (for people that doesn't use our client)).

@hsanjuan
Copy link
Collaborator

ipfs-cluster status --help print filter value instead of just filter

.// at end of the help message 
.
OPTIONS:
   --local         run operation only on the contacted peer
   --filter value  Comma seperated list of type tracker status and their aliases

Would you know why?

Because the --filter argument takes a value. It's not just a boolean flag.

api/rest/client/methods.go Outdated Show resolved Hide resolved
@@ -669,27 +669,74 @@ func (api *API) allocationHandler(w http.ResponseWriter, r *http.Request) {
}
}

func match(filters []string, status string) bool {
for _, filter := range filters {
Copy link
Collaborator

@hsanjuan hsanjuan Dec 21, 2018

Choose a reason for hiding this comment

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

We should convert to TrackerStatus (TrackerStatusFromString()) and compare with the original and not strings. The filter is a user-supplied string, so it should be checked for validity. We should probably move this function to api/types.go too. We will need to match API functionality in the Go API exposed by the main component (different PR).

Additionally, maybe worth to convert TrackerStatus from iota to 1 << iota and have TrackerStatusError = TrackerStatusPinError | TrackerStatusUnpinError | TrackerStatusClusterError and so on.. thoughts @lanzafame ? we did this with PinType and I think things were ok, it should not break anything since TrackerStatus is not persisted anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should convert to TrackerStatus (TrackerStatusFromString()) and compare with the original and not strings.

Can't do this with aliases such as error or queued

We will need to match API functionality in the Go API exposed by the main component

Don't understand this.
Do you mean this code ? https://github.com/ipfs/ipfs-cluster/blob/17599dac639cf6fd70343c72c24b7a8f037c733f/rpc_api.go#L111-L123
and https://github.com/ipfs/ipfs-cluster/blob/17599dac639cf6fd70343c72c24b7a8f037c733f/cluster.go#L753-L763

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@hsanjuan @lanzafame All comments addressed, except this one

Copy link
Collaborator

Choose a reason for hiding this comment

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

I mean https://github.com/ipfs/ipfs-cluster/blob/master/api/types.go#L582.

It would look like (untested):

diff --git a/api/types.go b/api/types.go
index 1234d09..bc3f426 100644
--- a/api/types.go
+++ b/api/types.go
@@ -34,7 +34,7 @@ var logger = logging.Logger("apitypes")
 // TrackerStatus values
 const (
        // IPFSStatus should never take this value
-       TrackerStatusBug TrackerStatus = iota
+       TrackerStatusBug TrackerStatus = 1 << iota
        // The cluster node is offline or not responding
        TrackerStatusClusterError
        // An error occurred pinning
@@ -60,6 +60,12 @@ const (
        TrackerStatusSharded
 )
 
+// Composite TrackerStatus
+const (
+       TrackerStatusError  = TrackerSTatusClusterError | TrackerStatusPinError | TrackerStatusUnpinError
+       TrackerStatusQueued = TrackerStatusPinQueued | TrackerStatusUnpinQueued
+)
+
 // TrackerStatus represents the status of a tracked Cid in the PinTracker
 type TrackerStatus int
 
@@ -75,6 +81,8 @@ var trackerStatusString = map[TrackerStatus]string{
        TrackerStatusRemote:       "remote",
        TrackerStatusPinQueued:    "pin_queued",
        TrackerStatusUnpinQueued:  "unpin_queued",
+       TrackerStatusError:        "error",
+       TrackerStatusQueued:       "queued",
 }


// Test with filter
var resp3 []api.GlobalPinInfoSerial
makeGet(t, rest, url(rest)+"/pins?filter=queue", &resp3)
Copy link
Collaborator

Choose a reason for hiding this comment

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

should be "queued" ?


When the --filter is passed, it will only fetch the peer information
where status of the pin matches with the filter value.
Valid filter values are tracker status types("pinned", "pin_error", "unpinning" etc),
Copy link
Collaborator

Choose a reason for hiding this comment

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

just list the values

`,
ArgsUsage: "[CID]",
Flags: []cli.Flag{
localFlag(),
cli.StringFlag{
Name: "filter",
Usage: "Comma seperated list of type tracker status and their aliases",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Comma-separated list of filters. The list of acceptable values are on the command help which is printed with the command a few lines over this.

@kishansagathiya
Copy link
Contributor Author

What is https://github.com/ipfs/ipfs-cluster/blob/master/sharness/t0025-ctl-status-report-commands.sh for ? It has more than tests for just ctl status. This would help me decide if I should create a new file for adding sharness tests for ctl status

api/types.go Outdated
@@ -93,6 +93,36 @@ func TrackerStatusFromString(str string) TrackerStatus {
return TrackerStatusBug
}

func IsFilterValid(filter string) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Adding Queued and Error to TrackerStatus, this should be a oneliner like TrackerStatusFromString(filter) != TrackerStatusBug. Also, probably better to convert to TrackerStatus first and then call a func (st TrackerStatus) IsValid() bool

List of tracker status types
https://github.com/ipfs/ipfs-cluster/blob/319c41cbf195b0453b8d1987991280d3121bac93/api/types.go#L66
Valid filter values are tracker status types(full list of tracker status
types includes "bug", "cluster_error", "pin_error", "unpin_error", "pinned",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please build this list programatically. You can add a helper function in api which loops the trackerStatusString and returns a list of valid status strings.

Copy link
Collaborator

@hsanjuan hsanjuan left a comment

Choose a reason for hiding this comment

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

Now that we have bit-flag TrackerStatuses, we can use bitwise comparsion to do matching:

// Match returns true if the tracker status matches the given filter.
// For example TrackerStatusPinError will match TrackerStatusPinError and TrackerStatusError
func (ts TrackerStatus) Match(filter TrackerStatus) bool {
    return ts & f > 0
}

api/types.go should not deal or operate with string versions of TrackerStatus.

api/rest will need:

  • A method to convert a query string in the form of "filter1,filter2,filter3" to TrackerStatus (worth removing whitespaces from the string before splitting). The filter is built the filter as the bitwise OR of the parsed values (ts1 || ts2 || ts3)
  • Use api.TrackerStatusFromString(pinInfo.Status).Match(filter) in the method filtering globalPinInfos.

This saves the most-inner loop which compares each Status to each filter value because now all the filter values can be represented as a single thing. Thus the complexity of this method is not exponentially worse with every extra filter value.

api/types.go Outdated Show resolved Hide resolved
api/types.go Outdated Show resolved Hide resolved
api/types.go Outdated Show resolved Hide resolved
api/types.go Outdated Show resolved Hide resolved
api/types.go Outdated Show resolved Hide resolved
api/types.go Outdated Show resolved Hide resolved
api/types.go Outdated Show resolved Hide resolved
api/types.go Outdated Show resolved Hide resolved
sona1111 and others added 10 commits January 5, 2019 14:44
License: MIT
Signed-off-by: Paul Jewell <sona1111@zoho.com>
License: MIT
Signed-off-by: Paul Jewell <sona1111@zoho.com>
-Fixed logic issue in match condition of 'filterStatus' function
-Added and verified success of test provided by @lanzafame
-Attempted to condense code and apply other cleanup provided by @lanzafame

License: MIT
Signed-off-by: Paul Jewell <sona1111@zoho.com>
-Changed some 'snake case' to 'camel case' in accordance with code climate

License: MIT
Signed-off-by: Paul Jewell <sona1111@zoho.com>
Added filter option to `ipfs-cluster-ctl status`

When the --filter is passed, it will only fetch the peer information
where status of the pin matches with the filter value.
Valid filter values are tracker status types(i.e., "pinned",
"pin_error", "unpinning" etc), an alias of tracker status type (i.e.,
"queued" or "error"), comma separated list of tracker status type
and/or it aliases(i.e., "error,pinning")

On passing invalid filter value no status information will be shown

In particular, the filter would remove elements from []GlobalPinInfo
when none of the peers in GlobalPinInfo match the filter. If one peer
in the GlobalPinInfo matches the filter, the whole object is returned,
including the information for the other peers which may or not match it.

filter option works on statusAll("GET /pins"). For fetching pin status
for a CID("GET /pins/<cid>"), filter option would have no effect

Fixes #445

License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
Added clients tests

Fixes #445

License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
Added a fail case where an invalid filter is passed in.
Update `api.rpcClient.Call` to `api.rpcClient.CallContext` and pass
in the Request context r.Context() so that context can be cancelled
when the request is cancelled by caller

Fixes #445

License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
Passing `make check`

Fixes #445

License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
Improved matching of filters and tracker status

Fixes #445

License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
@coveralls
Copy link

coveralls commented Jan 5, 2019

Coverage Status

Coverage increased (+0.1%) to 65.581% when pulling 964ced6 on issue_445 into 595db7a on master.

Optimized filter to tracker status matching by using bitwise
comparisions

License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
@ghost ghost assigned hsanjuan Jan 7, 2019
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
@hsanjuan
Copy link
Collaborator

hsanjuan commented Jan 7, 2019

@kishansagathiya I have ended wrapping this up. Please check my last commits. Sorry, it was difficult to figure out the details and realize of some small issues without actually messing with it myself.

@hsanjuan
Copy link
Collaborator

hsanjuan commented Jan 7, 2019

I have not tested this much though, would be grateful if you can check things still work as expected.

Copy link
Contributor Author

@kishansagathiya kishansagathiya left a comment

Choose a reason for hiding this comment

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

OK Tested locally,

However I have a small comment, let me know what you think about that. I will change it accordingly and fix tests.

api/rest/client/methods.go Show resolved Hide resolved
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
@@ -29,7 +29,7 @@ var testPeerID6, _ = peer.IDB58Decode("QmR8Vu6kZk7JvAN2rWVWgiduHatgBq2bb15Yyq8RR
func TestTrackerFromString(t *testing.T) {
testcases := []string{"undefined", "cluster_error", "pin_error", "unpin_error", "pinned", "pinning", "unpinning", "unpinned", "remote"}
for i, tc := range testcases {
if TrackerStatusFromString(tc).String() != TrackerStatus(1<<uint(i)).String() {
if tc != TrackerStatus(1<<uint(i)).String() && tc != TrackerStatus(0).String() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I had already fixed this

@hsanjuan
Copy link
Collaborator

hsanjuan commented Jan 8, 2019

@kishansagathiya please don't force push on 1) branches worked on by multiple people 2) In progress non-trivial reviews. It makes it difficult to follow up on changes.

@hsanjuan
Copy link
Collaborator

hsanjuan commented Jan 8, 2019

I'm going to force-push the original branch on top, the last commit should be reverted anyway.

License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
@hsanjuan
Copy link
Collaborator

hsanjuan commented Jan 8, 2019

Sorry! I just realized I had not fixed that test after all. Should be better now. :/

@kishansagathiya
Copy link
Contributor Author

@hsanjuan All checks have passed including travis pr check, somehow here it was showing pending(I have seen this happening before). Anyway I have restarted hopefully, that problem wont appear again.

@kishansagathiya
Copy link
Contributor Author

@hsanjuan finally after two reruns, phew!

@hsanjuan
Copy link
Collaborator

hsanjuan commented Jan 8, 2019

Hmm yeah, every few weeks I spend a couple of days figuring out why tests have become flaky. Maybe it's time for a new round.

@hsanjuan hsanjuan merged commit d80f3ee into master Jan 8, 2019
@ghost ghost removed the status/in-progress In progress label Jan 8, 2019
@hsanjuan hsanjuan deleted the issue_445 branch January 8, 2019 17:26
@hsanjuan hsanjuan mentioned this pull request Jan 8, 2019
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.

None yet

5 participants