analytics: Send ZULIP_MERGE_BASE to the bouncer.

This commit is contained in:
Mateusz Mandera 2024-06-23 02:50:05 +02:00 committed by Tim Abbott
parent 95a2ce6ed6
commit f8616fa013
5 changed files with 46 additions and 7 deletions

View File

@ -12,7 +12,7 @@ from pydantic import UUID4, BaseModel, ConfigDict, Field, Json, field_validator
from analytics.lib.counts import LOGGING_COUNT_STAT_PROPERTIES_NOT_SENT_TO_BOUNCER from analytics.lib.counts import LOGGING_COUNT_STAT_PROPERTIES_NOT_SENT_TO_BOUNCER
from analytics.models import InstallationCount, RealmCount from analytics.models import InstallationCount, RealmCount
from version import API_FEATURE_LEVEL, ZULIP_VERSION from version import API_FEATURE_LEVEL, ZULIP_MERGE_BASE, ZULIP_VERSION
from zerver.actions.realm_settings import ( from zerver.actions.realm_settings import (
do_set_push_notifications_enabled_end_timestamp, do_set_push_notifications_enabled_end_timestamp,
do_set_realm_property, do_set_realm_property,
@ -107,6 +107,7 @@ class AnalyticsRequest(BaseModel):
realmauditlog_rows: Optional[Json[List[RealmAuditLogDataForAnalytics]]] = None realmauditlog_rows: Optional[Json[List[RealmAuditLogDataForAnalytics]]] = None
realms: Json[List[RealmDataForAnalytics]] realms: Json[List[RealmDataForAnalytics]]
version: Optional[Json[str]] version: Optional[Json[str]]
merge_base: Optional[Json[str]]
api_feature_level: Optional[Json[int]] api_feature_level: Optional[Json[int]]
@ -423,6 +424,7 @@ def send_server_data_to_push_bouncer(consider_usage_statistics: bool = True) ->
realmauditlog_rows=realmauditlog_data, realmauditlog_rows=realmauditlog_data,
realms=get_realms_info_for_push_bouncer(), realms=get_realms_info_for_push_bouncer(),
version=ZULIP_VERSION, version=ZULIP_VERSION,
merge_base=ZULIP_MERGE_BASE,
api_feature_level=API_FEATURE_LEVEL, api_feature_level=API_FEATURE_LEVEL,
) )

View File

@ -1832,12 +1832,15 @@ class AnalyticsBouncerTest(BouncerTestCase):
realmauditlog_rows=realmauditlog_data, realmauditlog_rows=realmauditlog_data,
realms=[], realms=[],
version=None, version=None,
merge_base=None,
api_feature_level=None, api_feature_level=None,
) )
result = self.uuid_post( result = self.uuid_post(
self.server_uuid, self.server_uuid,
"/api/v1/remotes/server/analytics", "/api/v1/remotes/server/analytics",
request.model_dump(round_trip=True, exclude={"realms", "version", "api_feature_level"}), request.model_dump(
round_trip=True, exclude={"realms", "version", "merge_base", "api_feature_level"}
),
subdomain="", subdomain="",
) )
self.assert_json_error(result, "Data is out of order.") self.assert_json_error(result, "Data is out of order.")
@ -1871,12 +1874,15 @@ class AnalyticsBouncerTest(BouncerTestCase):
realmauditlog_rows=[], realmauditlog_rows=[],
realms=realms_data, realms=realms_data,
version=None, version=None,
merge_base=None,
api_feature_level=None, api_feature_level=None,
) )
result = self.uuid_post( result = self.uuid_post(
self.server_uuid, self.server_uuid,
"/api/v1/remotes/server/analytics", "/api/v1/remotes/server/analytics",
request.model_dump(round_trip=True, exclude={"version", "api_feature_level"}), request.model_dump(
round_trip=True, exclude={"version", "merge_base", "api_feature_level"}
),
subdomain="", subdomain="",
) )
self.assert_json_error( self.assert_json_error(
@ -1928,12 +1934,15 @@ class AnalyticsBouncerTest(BouncerTestCase):
realmauditlog_rows=realmauditlog_data, realmauditlog_rows=realmauditlog_data,
realms=[], realms=[],
version=None, version=None,
merge_base=None,
api_feature_level=None, api_feature_level=None,
) )
result = self.uuid_post( result = self.uuid_post(
self.server_uuid, self.server_uuid,
"/api/v1/remotes/server/analytics", "/api/v1/remotes/server/analytics",
request.model_dump(round_trip=True, exclude={"version", "api_feature_level"}), request.model_dump(
round_trip=True, exclude={"version", "merge_base", "api_feature_level"}
),
subdomain="", subdomain="",
) )
self.assert_json_error(result, "Invalid event type.") self.assert_json_error(result, "Invalid event type.")
@ -1954,12 +1963,15 @@ class AnalyticsBouncerTest(BouncerTestCase):
realmauditlog_rows=realmauditlog_data, realmauditlog_rows=realmauditlog_data,
realms=[], realms=[],
version=None, version=None,
merge_base=None,
api_feature_level=None, api_feature_level=None,
) )
result = self.uuid_post( result = self.uuid_post(
self.server_uuid, self.server_uuid,
"/api/v1/remotes/server/analytics", "/api/v1/remotes/server/analytics",
request.model_dump(round_trip=True, exclude={"version", "api_feature_level"}), request.model_dump(
round_trip=True, exclude={"version", "merge_base", "api_feature_level"}
),
subdomain="", subdomain="",
) )
self.assert_json_success(result) self.assert_json_success(result)

View File

@ -0,0 +1,17 @@
# Generated by Django 5.0.6 on 2024-06-23 00:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("zilencer", "0063_convert_ids_to_bigints"),
]
operations = [
migrations.AddField(
model_name="remotezulipserver",
name="last_merge_base",
field=models.CharField(max_length=128, null=True),
),
]

View File

@ -35,6 +35,7 @@ class RemoteZulipServer(models.Model):
API_KEY_LENGTH = 64 API_KEY_LENGTH = 64
HOSTNAME_MAX_LENGTH = 128 HOSTNAME_MAX_LENGTH = 128
VERSION_MAX_LENGTH = 128 VERSION_MAX_LENGTH = 128
MERGE_BASE_MAX_LENGTH = 128
# The unique UUID (`zulip_org_id`) and API key (`zulip_org_key`) # The unique UUID (`zulip_org_id`) and API key (`zulip_org_key`)
# for this remote server registration. # for this remote server registration.
@ -49,6 +50,7 @@ class RemoteZulipServer(models.Model):
last_updated = models.DateTimeField("last updated", auto_now=True) last_updated = models.DateTimeField("last updated", auto_now=True)
last_request_datetime = models.DateTimeField(null=True) last_request_datetime = models.DateTimeField(null=True)
last_version = models.CharField(max_length=VERSION_MAX_LENGTH, null=True) last_version = models.CharField(max_length=VERSION_MAX_LENGTH, null=True)
last_merge_base = models.CharField(max_length=MERGE_BASE_MAX_LENGTH, null=True)
last_api_feature_level = models.PositiveIntegerField(null=True) last_api_feature_level = models.PositiveIntegerField(null=True)
# Whether the server registration has been deactivated. # Whether the server registration has been deactivated.

View File

@ -1147,6 +1147,7 @@ def remote_server_post_analytics(
realmauditlog_rows: Optional[Json[List[RealmAuditLogDataForAnalytics]]] = None, realmauditlog_rows: Optional[Json[List[RealmAuditLogDataForAnalytics]]] = None,
realms: Optional[Json[List[RealmDataForAnalytics]]] = None, realms: Optional[Json[List[RealmDataForAnalytics]]] = None,
version: Optional[Json[str]] = None, version: Optional[Json[str]] = None,
merge_base: Optional[Json[str]] = None,
api_feature_level: Optional[Json[int]] = None, api_feature_level: Optional[Json[int]] = None,
) -> HttpResponse: ) -> HttpResponse:
# Lock the server, preventing this from racing with other # Lock the server, preventing this from racing with other
@ -1156,10 +1157,15 @@ def remote_server_post_analytics(
remote_server_version_updated = False remote_server_version_updated = False
if version is not None: if version is not None:
version = version[0 : RemoteZulipServer.VERSION_MAX_LENGTH] version = version[0 : RemoteZulipServer.VERSION_MAX_LENGTH]
if version != server.last_version or api_feature_level != server.last_api_feature_level: if (
version != server.last_version
or merge_base != server.last_merge_base
or api_feature_level != server.last_api_feature_level
):
server.last_version = version server.last_version = version
server.last_merge_base = merge_base
server.last_api_feature_level = api_feature_level server.last_api_feature_level = api_feature_level
server.save(update_fields=["last_version", "last_api_feature_level"]) server.save(update_fields=["last_version", "last_merge_base", "last_api_feature_level"])
remote_server_version_updated = True remote_server_version_updated = True
validate_incoming_table_data( validate_incoming_table_data(