From: Peter Amstutz Date: Mon, 9 Nov 2020 18:42:12 +0000 (-0500) Subject: 17022: Start work on user activity reporting script X-Git-Tag: 2.2.0~203^2~9 X-Git-Url: https://git.arvados.org/arvados.git/commitdiff_plain/aaa37d337cfab7eaa9b616cdccb2ea662dd6c7a8 17022: Start work on user activity reporting script Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- diff --git a/doc/api/methods.html.textile.liquid b/doc/api/methods.html.textile.liquid index 872a1bca71..b0a3c5e2f8 100644 --- a/doc/api/methods.html.textile.liquid +++ b/doc/api/methods.html.textile.liquid @@ -73,9 +73,9 @@ table(table table-bordered table-condensed). |limit |integer|Maximum number of resources to return. If not provided, server will provide a default limit. Server may also impose a maximum number of records that can be returned in a single request.|query| |offset |integer|Skip the first 'offset' number of resources that would be returned under the given filter conditions.|query| |filters |array |"Conditions for selecting resources to return.":#filters|query| -|order |array |Attributes to use as sort keys to determine the order resources are returned, each optionally followed by @asc@ or @desc@ to indicate ascending or descending order. +|order |array |Attributes to use as sort keys to determine the order resources are returned, each optionally followed by @asc@ or @desc@ to indicate ascending or descending order. (If not specified, it will be ascending). Example: @["head_uuid asc","modified_at desc"]@ -Default: @["created_at desc"]@|query| +Default: @["modified_at desc", "uuid asc"]@|query| |select |array |Set of attributes to include in the response. Example: @["head_uuid","tail_uuid"]@ Default: all available attributes. As a special case, collections do not return "manifest_text" unless explicitly selected.|query| diff --git a/tools/user-activity/arv-user-activity.py b/tools/user-activity/arv-user-activity.py new file mode 100644 index 0000000000..e5e0f5385d --- /dev/null +++ b/tools/user-activity/arv-user-activity.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +# Copyright (C) The Arvados Authors. All rights reserved. +# +# SPDX-License-Identifier: AGPL-3.0 + +import argparse +import sys + +import arvados +import arvados.util + +def keyset_list_all(fn, order_key="created_at", num_retries=0, ascending=True, **kwargs): + pagesize = 1000 + kwargs["limit"] = pagesize + kwargs["count"] = 'none' + kwargs["order"] = ["%s %s" % (order_key, "asc" if ascending else "desc"), "uuid asc"] + other_filters = kwargs.get("filters", []) + + if "select" in kwargs and "uuid" not in kwargs["select"]: + kwargs["select"].append("uuid") + + nextpage = [] + tot = 0 + expect_full_page = True + seen_prevpage = set() + seen_thispage = set() + lastitem = None + prev_page_all_same_order_key = False + + while True: + kwargs["filters"] = nextpage+other_filters + items = fn(**kwargs).execute(num_retries=num_retries) + + if len(items["items"]) == 0: + if prev_page_all_same_order_key: + nextpage = [[order_key, ">" if ascending else "<", lastitem[order_key]]] + prev_page_all_same_order_key = False + continue + else: + return + + seen_prevpage = seen_thispage + seen_thispage = set() + + for i in items["items"]: + # In cases where there's more than one record with the + # same order key, the result could include records we + # already saw in the last page. Skip them. + if i["uuid"] in seen_prevpage: + continue + seen_thispage.add(i["uuid"]) + yield i + + firstitem = items["items"][0] + lastitem = items["items"][-1] + + if firstitem[order_key] == lastitem[order_key]: + # Got a page where every item has the same order key. + # Switch to using uuid for paging. + nextpage = [[order_key, "=", lastitem[order_key]], ["uuid", ">", lastitem["uuid"]]] + prev_page_all_same_order_key = True + else: + # Start from the last order key seen, but skip the last + # known uuid to avoid retrieving the same row twice. If + # there are multiple rows with the same order key it is + # still likely we'll end up retrieving duplicate rows. + # That's handled by tracking the "seen" rows for each page + # so they can be skipped if they show up on the next page. + nextpage = [[order_key, ">=" if ascending else "<=", lastitem[order_key]], ["uuid", "!=", lastitem["uuid"]]] + prev_page_all_same_order_key = False + + +def parse_arguments(arguments): + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument('--timespan', type=str) + args = arg_parser.parse_args(arguments) + return args + +def main(arguments): + args = parse_arguments(arguments) + + arv = arvados.api() + + events = keyset_list_all(arv.logs().list, filters=[["created_at", ">=", "2020-11-05T14:51:42-05:00"]]) + + users = {} + + for e in events: + if e["event_type"] == "create" and e["object_uuid"][6:11] == "tpzed": + users.setdefault(e["object_uuid"], []) + users[e["object_uuid"]].append("User was created") + + if e["event_type"] == "create" and e["object_uuid"][6:11] == "xvhdp": + users.setdefault(e["object_owner_uuid"], []) + users[e["object_owner_uuid"]].append("Ran a container") + + if e["event_type"] == "create" and e["object_uuid"][6:11] == "j7d0g": + users.setdefault(e["object_owner_uuid"], []) + users[e["object_owner_uuid"]].append("Created a project") + + for k,v in users.items(): + print("%s:" % k) + for ev in v: + print(" %s" % ev) + + +main(sys.argv[1:])