Repository: pulp/pulpcore

Issue:
analytics.pulpproject.org should collect statistics about RBAC usage 
The proposed metrics are outlined here[0].

[0] https://github.com/pulp/analytics.pulpproject.org/issues/84


Discussion:

Resolving patch:
diff --git a/pulpcore/app/protobuf/analytics_pb2.py b/pulpcore/app/protobuf/analytics_pb2.py
--- a/pulpcore/app/protobuf/analytics_pb2.py
+++ b/pulpcore/app/protobuf/analytics_pb2.py
@@ -2,76 +2,32 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: analytics.proto
 """Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
 from google.protobuf import descriptor_pool as _descriptor_pool
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
 from google.protobuf import symbol_database as _symbol_database
-
 # @@protoc_insertion_point(imports)
 
 _sym_db = _symbol_database.Default()
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
-    b'\n\x0f\x61nalytics.proto"\xe7\x02\n\tAnalytics\x12\x11\n\tsystem_id\x18\x01 \x02(\t\x12\x39\n\x13online_content_apps\x18\x02 \x01(\x0b\x32\x1c.Analytics.OnlineContentApps\x12\x30\n\x0eonline_workers\x18\x03 \x01(\x0b\x32\x18.Analytics.OnlineWorkers\x12(\n\ncomponents\x18\x04 \x03(\x0b\x32\x14.Analytics.Component\x12\x1a\n\x12postgresql_version\x18\x05 \x01(\r\x1a\x35\n\x11OnlineContentApps\x12\x11\n\tprocesses\x18\x01 \x01(\r\x12\r\n\x05hosts\x18\x02 \x01(\r\x1a\x31\n\rOnlineWorkers\x12\x11\n\tprocesses\x18\x01 \x01(\r\x12\r\n\x05hosts\x18\x02 \x01(\r\x1a*\n\tComponent\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0f\n\x07version\x18\x02 \x02(\t'
-)
 
 
-_ANALYTICS = DESCRIPTOR.message_types_by_name["Analytics"]
-_ANALYTICS_ONLINECONTENTAPPS = _ANALYTICS.nested_types_by_name["OnlineContentApps"]
-_ANALYTICS_ONLINEWORKERS = _ANALYTICS.nested_types_by_name["OnlineWorkers"]
-_ANALYTICS_COMPONENT = _ANALYTICS.nested_types_by_name["Component"]
-Analytics = _reflection.GeneratedProtocolMessageType(
-    "Analytics",
-    (_message.Message,),
-    {
-        "OnlineContentApps": _reflection.GeneratedProtocolMessageType(
-            "OnlineContentApps",
-            (_message.Message,),
-            {
-                "DESCRIPTOR": _ANALYTICS_ONLINECONTENTAPPS,
-                "__module__": "analytics_pb2"
-                # @@protoc_insertion_point(class_scope:Analytics.OnlineContentApps)
-            },
-        ),
-        "OnlineWorkers": _reflection.GeneratedProtocolMessageType(
-            "OnlineWorkers",
-            (_message.Message,),
-            {
-                "DESCRIPTOR": _ANALYTICS_ONLINEWORKERS,
-                "__module__": "analytics_pb2"
-                # @@protoc_insertion_point(class_scope:Analytics.OnlineWorkers)
-            },
-        ),
-        "Component": _reflection.GeneratedProtocolMessageType(
-            "Component",
-            (_message.Message,),
-            {
-                "DESCRIPTOR": _ANALYTICS_COMPONENT,
-                "__module__": "analytics_pb2"
-                # @@protoc_insertion_point(class_scope:Analytics.Component)
-            },
-        ),
-        "DESCRIPTOR": _ANALYTICS,
-        "__module__": "analytics_pb2"
-        # @@protoc_insertion_point(class_scope:Analytics)
-    },
-)
-_sym_db.RegisterMessage(Analytics)
-_sym_db.RegisterMessage(Analytics.OnlineContentApps)
-_sym_db.RegisterMessage(Analytics.OnlineWorkers)
-_sym_db.RegisterMessage(Analytics.Component)
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0f\x61nalytics.proto\"\x84\x04\n\tAnalytics\x12\x11\n\tsystem_id\x18\x01 \x02(\t\x12\x39\n\x13online_content_apps\x18\x02 \x01(\x0b\x32\x1c.Analytics.OnlineContentApps\x12\x30\n\x0eonline_workers\x18\x03 \x01(\x0b\x32\x18.Analytics.OnlineWorkers\x12(\n\ncomponents\x18\x04 \x03(\x0b\x32\x14.Analytics.Component\x12\x1a\n\x12postgresql_version\x18\x05 \x01(\r\x12(\n\nrbac_stats\x18\x06 \x01(\x0b\x32\x14.Analytics.RBACStats\x1a\x35\n\x11OnlineContentApps\x12\x11\n\tprocesses\x18\x01 \x01(\r\x12\r\n\x05hosts\x18\x02 \x01(\r\x1a\x31\n\rOnlineWorkers\x12\x11\n\tprocesses\x18\x01 \x01(\r\x12\r\n\x05hosts\x18\x02 \x01(\r\x1a*\n\tComponent\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0f\n\x07version\x18\x02 \x02(\t\x1aq\n\tRBACStats\x12\r\n\x05users\x18\x01 \x01(\r\x12\x0e\n\x06groups\x18\x02 \x01(\r\x12\x0f\n\x07\x64omains\x18\x03 \x01(\r\x12\x1e\n\x16\x63ustom_access_policies\x18\x04 \x01(\r\x12\x14\n\x0c\x63ustom_roles\x18\x05 \x01(\r')
 
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'analytics_pb2', globals())
 if _descriptor._USE_C_DESCRIPTORS == False:
 
-    DESCRIPTOR._options = None
-    _ANALYTICS._serialized_start = 20
-    _ANALYTICS._serialized_end = 379
-    _ANALYTICS_ONLINECONTENTAPPS._serialized_start = 231
-    _ANALYTICS_ONLINECONTENTAPPS._serialized_end = 284
-    _ANALYTICS_ONLINEWORKERS._serialized_start = 286
-    _ANALYTICS_ONLINEWORKERS._serialized_end = 335
-    _ANALYTICS_COMPONENT._serialized_start = 337
-    _ANALYTICS_COMPONENT._serialized_end = 379
+  DESCRIPTOR._options = None
+  _ANALYTICS._serialized_start=20
+  _ANALYTICS._serialized_end=536
+  _ANALYTICS_ONLINECONTENTAPPS._serialized_start=273
+  _ANALYTICS_ONLINECONTENTAPPS._serialized_end=326
+  _ANALYTICS_ONLINEWORKERS._serialized_start=328
+  _ANALYTICS_ONLINEWORKERS._serialized_end=377
+  _ANALYTICS_COMPONENT._serialized_start=379
+  _ANALYTICS_COMPONENT._serialized_end=421
+  _ANALYTICS_RBACSTATS._serialized_start=423
+  _ANALYTICS_RBACSTATS._serialized_end=536
 # @@protoc_insertion_point(module_scope)
diff --git a/pulpcore/app/tasks/analytics.py b/pulpcore/app/tasks/analytics.py
--- a/pulpcore/app/tasks/analytics.py
+++ b/pulpcore/app/tasks/analytics.py
@@ -6,11 +6,14 @@
 import async_timeout
 
 from asgiref.sync import sync_to_async
+from django.conf import settings
 from django.db import connection
+from django.contrib.auth import get_user_model
 from google.protobuf.json_format import MessageToJson
 
 from pulpcore.app.apps import pulp_plugin_configs
-from pulpcore.app.models import SystemID
+from pulpcore.app.models import SystemID, Group, Domain, AccessPolicy
+from pulpcore.app.models.role import Role
 from pulpcore.app.models.status import ContentAppStatus
 from pulpcore.app.models.task import Worker
 from pulpcore.app.protobuf.analytics_pb2 import Analytics
@@ -23,6 +26,9 @@
 DEV_URL = "https://dev.analytics.pulpproject.org/"
 
 
+User = get_user_model()
+
+
 def get_analytics_posting_url():
     """
     Return either the dev or production analytics FQDN url.
@@ -85,6 +91,21 @@ async def _system_id(analytics):
     analytics.system_id = str(system_id_obj.pk)
 
 
+async def _rbac_stats(analytics):
+    analytics.rbac_stats.users = await sync_to_async(User.objects.count)()
+    analytics.rbac_stats.groups = await sync_to_async(Group.objects.count)()
+    if settings.DOMAIN_ENABLED:
+        analytics.rbac_stats.domains = await sync_to_async(Domain.objects.count)()
+    else:
+        analytics.rbac_stats.domains = 0
+    analytics.rbac_stats.custom_access_policies = await sync_to_async(
+        AccessPolicy.objects.filter(customized=True).count
+    )()
+    analytics.rbac_stats.custom_roles = await sync_to_async(
+        Role.objects.filter(locked=False).count
+    )()
+
+
 async def post_analytics():
     url = get_analytics_posting_url()
 
@@ -96,6 +117,7 @@ async def post_analytics():
         _online_content_apps_data(analytics),
         _online_workers_data(analytics),
         _postgresql_version(analytics),
+        _rbac_stats(analytics),
     )
 
     await asyncio.gather(*awaitables)


Test patch: