Because * We need to be able to send experiments to the relevant remote settings bucket for desktop and mobile experiments This commit * Moves the kinto bucket/collection configuration out of environment and into settings because it's consistent across all deployments * Adds the mobile collection constant * Modifies the kinto tasks to push to the relevant collection and monitor all collections for live/complete changes
This commit is contained in:
Родитель
ffa8f629a3
Коммит
9c42664be6
|
@ -24,10 +24,6 @@ FEATURE_ANALYSIS=False
|
|||
FEATURE_MESSAGE_TYPE=False
|
||||
GOOGLE_APPLICATION_CREDENTIALS=
|
||||
HOSTNAME=localhost
|
||||
KINTO_BUCKET_MAIN=main
|
||||
KINTO_BUCKET=main-workspace
|
||||
KINTO_COLLECTION=messaging-experiments
|
||||
KINTO_COLLECTION_NIMBUS=nimbus-desktop-experiments
|
||||
KINTO_HOST=http://kinto:8888/v1
|
||||
KINTO_PASS=experimenter
|
||||
KINTO_USER=experimenter
|
||||
|
|
|
@ -9,9 +9,11 @@ REVIEW_USER = REVIEW_PASS = "review"
|
|||
EXPERIMENTER_USER = os.environ["KINTO_USER"]
|
||||
EXPERIMENTER_PASS = os.environ["KINTO_PASS"]
|
||||
KINTO_HOST = os.environ["KINTO_HOST"]
|
||||
KINTO_BUCKET = os.environ["KINTO_BUCKET"]
|
||||
KINTO_COLLECTION_LEGACY = (os.environ["KINTO_COLLECTION"],)
|
||||
KINTO_COLLECTION_NIMBUS = os.environ["KINTO_COLLECTION_NIMBUS"]
|
||||
KINTO_BUCKET = "main-workspace"
|
||||
KINTO_BUCKET_MAIN = "main"
|
||||
KINTO_COLLECTION_LEGACY = "messaging-experiments"
|
||||
KINTO_COLLECTION_NIMBUS_DESKTOP = "nimbus-desktop-experiments"
|
||||
KINTO_COLLECTION_NIMBUS_MOBILE = "nimbus-mobile-experiments"
|
||||
|
||||
|
||||
def create_user(user, passw):
|
||||
|
@ -40,7 +42,11 @@ print(
|
|||
)
|
||||
|
||||
|
||||
for collection in [KINTO_COLLECTION_LEGACY, KINTO_COLLECTION_NIMBUS]:
|
||||
for collection in [
|
||||
KINTO_COLLECTION_LEGACY,
|
||||
KINTO_COLLECTION_NIMBUS_DESKTOP,
|
||||
KINTO_COLLECTION_NIMBUS_MOBILE,
|
||||
]:
|
||||
print(">>>> Creating kinto group: editors")
|
||||
print(
|
||||
client.create_group(
|
||||
|
|
|
@ -3455,8 +3455,7 @@
|
|||
"application": {
|
||||
"enum": [
|
||||
"firefox-desktop",
|
||||
"fenix",
|
||||
"reference-browser"
|
||||
"fenix"
|
||||
],
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
|
|
|
@ -3467,8 +3467,7 @@
|
|||
"application": {
|
||||
"enum": [
|
||||
"firefox-desktop",
|
||||
"fenix",
|
||||
"reference-browser"
|
||||
"fenix"
|
||||
],
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from dataclasses import dataclass
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
|
||||
|
@ -60,7 +61,11 @@ class NimbusConstants(object):
|
|||
class Application(models.TextChoices):
|
||||
DESKTOP = "firefox-desktop"
|
||||
FENIX = "fenix"
|
||||
REFERENCE = "reference-browser"
|
||||
|
||||
KINTO_APPLICATION_COLLECTION = {
|
||||
Application.DESKTOP: settings.KINTO_COLLECTION_NIMBUS_DESKTOP,
|
||||
Application.FENIX: settings.KINTO_COLLECTION_NIMBUS_MOBILE,
|
||||
}
|
||||
|
||||
class Channel(models.TextChoices):
|
||||
DESKTOP_BETA = "Beta"
|
||||
|
@ -82,7 +87,6 @@ class NimbusConstants(object):
|
|||
Channel.FENIX_BETA,
|
||||
Channel.FENIX_RELEASE,
|
||||
],
|
||||
Application.REFERENCE: [Channel.REFERENCE_RELEASE],
|
||||
}
|
||||
|
||||
class Version(models.TextChoices):
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
# Generated by Django 3.0.7 on 2020-11-03 17:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("experiments", "0131_nimbus_remove_probe_set_m2m"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="nimbusexperiment",
|
||||
name="application",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[("firefox-desktop", "Desktop"), ("fenix", "Fenix")],
|
||||
max_length=255,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="nimbusfeatureconfig",
|
||||
name="application",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[("firefox-desktop", "Desktop"), ("fenix", "Fenix")],
|
||||
max_length=255,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -34,7 +34,6 @@ def nimbus_push_experiment_to_kinto(experiment_id):
|
|||
and push its data to the configured collection. If it fails for any reason, log the
|
||||
error and reraise it so it will be forwarded to sentry.
|
||||
"""
|
||||
kinto_client = KintoClient(settings.KINTO_COLLECTION_NIMBUS)
|
||||
|
||||
metrics.incr("push_experiment_to_kinto.started")
|
||||
|
||||
|
@ -42,6 +41,10 @@ def nimbus_push_experiment_to_kinto(experiment_id):
|
|||
experiment = NimbusExperiment.objects.get(id=experiment_id)
|
||||
logger.info(f"Pushing {experiment} to Kinto")
|
||||
|
||||
kinto_client = KintoClient(
|
||||
NimbusExperiment.KINTO_APPLICATION_COLLECTION[experiment.application]
|
||||
)
|
||||
|
||||
if not NimbusBucketRange.objects.filter(experiment=experiment).exists():
|
||||
NimbusIsolationGroup.request_isolation_group_buckets(
|
||||
experiment.slug,
|
||||
|
@ -81,37 +84,38 @@ def nimbus_check_kinto_push_queue():
|
|||
- Gets the list of all experiments ready to be pushed to kinto and pushes the first
|
||||
one
|
||||
"""
|
||||
kinto_client = KintoClient(settings.KINTO_COLLECTION_NIMBUS)
|
||||
|
||||
metrics.incr("check_kinto_push_queue.started")
|
||||
|
||||
rejected_collection_data = kinto_client.get_rejected_collection_data()
|
||||
if rejected_collection_data:
|
||||
rejected_slug = kinto_client.get_rejected_record()
|
||||
experiment = NimbusExperiment.objects.get(slug=rejected_slug)
|
||||
experiment.status = NimbusExperiment.Status.DRAFT
|
||||
experiment.save()
|
||||
for application, collection in NimbusExperiment.KINTO_APPLICATION_COLLECTION.items():
|
||||
kinto_client = KintoClient(collection)
|
||||
|
||||
generate_nimbus_changelog(
|
||||
experiment,
|
||||
get_kinto_user(),
|
||||
message=f'Rejected: {rejected_collection_data["last_reviewer_comment"]}',
|
||||
rejected_collection_data = kinto_client.get_rejected_collection_data()
|
||||
if rejected_collection_data:
|
||||
rejected_slug = kinto_client.get_rejected_record()
|
||||
experiment = NimbusExperiment.objects.get(slug=rejected_slug)
|
||||
experiment.status = NimbusExperiment.Status.DRAFT
|
||||
experiment.save()
|
||||
|
||||
generate_nimbus_changelog(
|
||||
experiment,
|
||||
get_kinto_user(),
|
||||
message=f'Rejected: {rejected_collection_data["last_reviewer_comment"]}',
|
||||
)
|
||||
|
||||
kinto_client.delete_rejected_record(rejected_slug)
|
||||
|
||||
if kinto_client.has_pending_review():
|
||||
metrics.incr("check_kinto_push_queue.{collection}_pending_review")
|
||||
return
|
||||
|
||||
queued_experiments = NimbusExperiment.objects.filter(
|
||||
status=NimbusExperiment.Status.REVIEW, application=application
|
||||
)
|
||||
|
||||
kinto_client.delete_rejected_record(rejected_slug)
|
||||
|
||||
if kinto_client.has_pending_review():
|
||||
metrics.incr("check_kinto_push_queue.pending_review")
|
||||
return
|
||||
|
||||
queued_experiments = NimbusExperiment.objects.filter(
|
||||
status=NimbusExperiment.Status.REVIEW
|
||||
)
|
||||
if queued_experiments.exists():
|
||||
nimbus_push_experiment_to_kinto.delay(queued_experiments.first().id)
|
||||
metrics.incr("check_kinto_push_queue.queued_experiment_selected")
|
||||
else:
|
||||
metrics.incr("check_kinto_push_queue.no_experiments_queued")
|
||||
if queued_experiments.exists():
|
||||
nimbus_push_experiment_to_kinto.delay(queued_experiments.first().id)
|
||||
metrics.incr("check_kinto_push_queue.{collection}_queued_experiment_selected")
|
||||
else:
|
||||
metrics.incr("check_kinto_push_queue.{collection}_no_experiments_queued")
|
||||
|
||||
metrics.incr("check_kinto_push_queue.completed")
|
||||
|
||||
|
@ -124,31 +128,32 @@ def nimbus_check_experiments_are_live():
|
|||
present in the collection but are not yet marked as live in the database and marks
|
||||
them as live.
|
||||
"""
|
||||
kinto_client = KintoClient(settings.KINTO_COLLECTION_NIMBUS)
|
||||
|
||||
metrics.incr("check_experiments_are_live.started")
|
||||
|
||||
accepted_experiments = NimbusExperiment.objects.filter(
|
||||
status=NimbusExperiment.Status.ACCEPTED
|
||||
)
|
||||
for collection in NimbusExperiment.KINTO_APPLICATION_COLLECTION.values():
|
||||
kinto_client = KintoClient(collection)
|
||||
|
||||
records = kinto_client.get_main_records()
|
||||
record_ids = [r.get("id") for r in records]
|
||||
accepted_experiments = NimbusExperiment.objects.filter(
|
||||
status=NimbusExperiment.Status.ACCEPTED
|
||||
)
|
||||
|
||||
for experiment in accepted_experiments:
|
||||
if experiment.slug in record_ids:
|
||||
logger.info(
|
||||
"{experiment} status is being updated to live".format(
|
||||
experiment=experiment
|
||||
records = kinto_client.get_main_records()
|
||||
record_ids = [r.get("id") for r in records]
|
||||
|
||||
for experiment in accepted_experiments:
|
||||
if experiment.slug in record_ids:
|
||||
logger.info(
|
||||
"{experiment} status is being updated to live".format(
|
||||
experiment=experiment
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
experiment.status = NimbusExperiment.Status.LIVE
|
||||
experiment.save()
|
||||
experiment.status = NimbusExperiment.Status.LIVE
|
||||
experiment.save()
|
||||
|
||||
generate_nimbus_changelog(experiment, get_kinto_user())
|
||||
generate_nimbus_changelog(experiment, get_kinto_user())
|
||||
|
||||
logger.info("{experiment} status is set to Live")
|
||||
logger.info("{experiment} status is set to Live")
|
||||
|
||||
metrics.incr("check_experiments_are_live.completed")
|
||||
|
||||
|
@ -161,38 +166,39 @@ def nimbus_check_experiments_are_complete():
|
|||
marked as live in the database but missing from the collection, indicating that they
|
||||
are no longer live and can be marked as complete.
|
||||
"""
|
||||
kinto_client = KintoClient(settings.KINTO_COLLECTION_NIMBUS)
|
||||
|
||||
metrics.incr("check_experiments_are_complete.started")
|
||||
|
||||
live_experiments = NimbusExperiment.objects.filter(
|
||||
status=NimbusExperiment.Status.LIVE
|
||||
)
|
||||
for collection in NimbusExperiment.KINTO_APPLICATION_COLLECTION.values():
|
||||
kinto_client = KintoClient(collection)
|
||||
|
||||
records = kinto_client.get_main_records()
|
||||
record_ids = [r.get("id") for r in records]
|
||||
live_experiments = NimbusExperiment.objects.filter(
|
||||
status=NimbusExperiment.Status.LIVE
|
||||
)
|
||||
|
||||
for experiment in live_experiments:
|
||||
if (
|
||||
experiment.should_end
|
||||
and not experiment.emails.filter(
|
||||
type=NimbusExperiment.EmailType.EXPERIMENT_END
|
||||
).exists()
|
||||
):
|
||||
nimbus_send_experiment_ending_email(experiment)
|
||||
records = kinto_client.get_main_records()
|
||||
record_ids = [r.get("id") for r in records]
|
||||
|
||||
if experiment.slug not in record_ids:
|
||||
logger.info(
|
||||
"{experiment} status is being updated to complete".format(
|
||||
experiment=experiment
|
||||
for experiment in live_experiments:
|
||||
if (
|
||||
experiment.should_end
|
||||
and not experiment.emails.filter(
|
||||
type=NimbusExperiment.EmailType.EXPERIMENT_END
|
||||
).exists()
|
||||
):
|
||||
nimbus_send_experiment_ending_email(experiment)
|
||||
|
||||
if experiment.slug not in record_ids:
|
||||
logger.info(
|
||||
"{experiment} status is being updated to complete".format(
|
||||
experiment=experiment
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
experiment.status = NimbusExperiment.Status.COMPLETE
|
||||
experiment.save()
|
||||
experiment.status = NimbusExperiment.Status.COMPLETE
|
||||
experiment.save()
|
||||
|
||||
generate_nimbus_changelog(experiment, get_kinto_user())
|
||||
generate_nimbus_changelog(experiment, get_kinto_user())
|
||||
|
||||
logger.info("{experiment} status is set to Complete")
|
||||
logger.info("{experiment} status is set to Complete")
|
||||
|
||||
metrics.incr("check_experiments_are_complete.completed")
|
||||
|
|
|
@ -18,31 +18,56 @@ from experimenter.kinto.tests.mixins import MockKintoClientMixin
|
|||
|
||||
|
||||
class TestPushExperimentToKintoTask(MockKintoClientMixin, TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.experiment = NimbusExperimentFactory.create_with_status(
|
||||
def test_push_experiment_to_kinto_sends_desktop_experiment_data(self):
|
||||
experiment = NimbusExperimentFactory.create_with_status(
|
||||
NimbusExperiment.Status.DRAFT,
|
||||
application=NimbusExperiment.Application.DESKTOP,
|
||||
)
|
||||
|
||||
def test_push_experiment_to_kinto_sends_experiment_data(self):
|
||||
tasks.nimbus_push_experiment_to_kinto(self.experiment.id)
|
||||
tasks.nimbus_push_experiment_to_kinto(experiment.id)
|
||||
|
||||
data = NimbusExperimentSerializer(self.experiment).data
|
||||
data = NimbusExperimentSerializer(experiment).data
|
||||
|
||||
self.assertTrue(
|
||||
NimbusBucketRange.objects.filter(experiment=self.experiment).exists()
|
||||
)
|
||||
self.assertTrue(NimbusBucketRange.objects.filter(experiment=experiment).exists())
|
||||
|
||||
self.mock_kinto_client.create_record.assert_called_with(
|
||||
data=data,
|
||||
collection=settings.KINTO_COLLECTION_NIMBUS,
|
||||
collection=settings.KINTO_COLLECTION_NIMBUS_DESKTOP,
|
||||
bucket=settings.KINTO_BUCKET,
|
||||
if_not_exists=True,
|
||||
)
|
||||
|
||||
self.assertTrue(
|
||||
NimbusChangeLog.objects.filter(
|
||||
experiment=self.experiment,
|
||||
experiment=experiment,
|
||||
changed_by__email=settings.KINTO_DEFAULT_CHANGELOG_USER,
|
||||
old_status=NimbusExperiment.Status.DRAFT,
|
||||
new_status=NimbusExperiment.Status.ACCEPTED,
|
||||
).exists()
|
||||
)
|
||||
|
||||
def test_push_experiment_to_kinto_sends_fenix__experiment_data(self):
|
||||
experiment = NimbusExperimentFactory.create_with_status(
|
||||
NimbusExperiment.Status.DRAFT,
|
||||
application=NimbusExperiment.Application.FENIX,
|
||||
)
|
||||
|
||||
tasks.nimbus_push_experiment_to_kinto(experiment.id)
|
||||
|
||||
data = NimbusExperimentSerializer(experiment).data
|
||||
|
||||
self.assertTrue(NimbusBucketRange.objects.filter(experiment=experiment).exists())
|
||||
|
||||
self.mock_kinto_client.create_record.assert_called_with(
|
||||
data=data,
|
||||
collection=settings.KINTO_COLLECTION_NIMBUS_MOBILE,
|
||||
bucket=settings.KINTO_BUCKET,
|
||||
if_not_exists=True,
|
||||
)
|
||||
|
||||
self.assertTrue(
|
||||
NimbusChangeLog.objects.filter(
|
||||
experiment=experiment,
|
||||
changed_by__email=settings.KINTO_DEFAULT_CHANGELOG_USER,
|
||||
old_status=NimbusExperiment.Status.DRAFT,
|
||||
new_status=NimbusExperiment.Status.ACCEPTED,
|
||||
|
@ -50,10 +75,12 @@ class TestPushExperimentToKintoTask(MockKintoClientMixin, TestCase):
|
|||
)
|
||||
|
||||
def test_push_experiment_to_kinto_reraises_exception(self):
|
||||
experiment = NimbusExperimentFactory.create_with_status(
|
||||
NimbusExperiment.Status.DRAFT,
|
||||
)
|
||||
self.mock_kinto_client.create_record.side_effect = Exception
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
tasks.nimbus_push_experiment_to_kinto(self.experiment.id)
|
||||
tasks.nimbus_push_experiment_to_kinto(experiment.id)
|
||||
|
||||
|
||||
class TestCheckKintoPushQueue(MockKintoClientMixin, TestCase):
|
||||
|
@ -106,10 +133,12 @@ class TestCheckKintoPushQueue(MockKintoClientMixin, TestCase):
|
|||
def test_check_with_reject_review(self):
|
||||
experiment = NimbusExperimentFactory.create_with_status(
|
||||
NimbusExperiment.Status.ACCEPTED,
|
||||
application=NimbusExperiment.Application.DESKTOP,
|
||||
)
|
||||
|
||||
self.mock_kinto_client.delete_record.return_value = {}
|
||||
self.mock_kinto_client.get_collection.side_effect = [
|
||||
# Desktop responses
|
||||
{
|
||||
"data": {
|
||||
"status": KINTO_REJECTED_STATUS,
|
||||
|
@ -117,13 +146,20 @@ class TestCheckKintoPushQueue(MockKintoClientMixin, TestCase):
|
|||
}
|
||||
},
|
||||
{"data": {"status": "anything"}},
|
||||
# Fenix responses
|
||||
{"data": {"status": "anything"}},
|
||||
{"data": {"status": "anything"}},
|
||||
]
|
||||
self.mock_kinto_client.get_records.side_effect = [
|
||||
# Desktop responses
|
||||
[{"id": "another-experiment"}],
|
||||
[
|
||||
{"id": "another-experiment"},
|
||||
{"id": experiment.slug},
|
||||
],
|
||||
# Fenix responses
|
||||
[],
|
||||
[],
|
||||
]
|
||||
tasks.nimbus_check_kinto_push_queue()
|
||||
|
||||
|
|
|
@ -406,10 +406,11 @@ FEATURE_ANALYSIS = config("FEATURE_ANALYSIS", default=False, cast=bool)
|
|||
KINTO_HOST = config("KINTO_HOST")
|
||||
KINTO_USER = config("KINTO_USER")
|
||||
KINTO_PASS = config("KINTO_PASS")
|
||||
KINTO_BUCKET = config("KINTO_BUCKET")
|
||||
KINTO_BUCKET_MAIN = config("KINTO_BUCKET_MAIN")
|
||||
KINTO_COLLECTION = config("KINTO_COLLECTION")
|
||||
KINTO_COLLECTION_NIMBUS = config("KINTO_COLLECTION_NIMBUS")
|
||||
KINTO_BUCKET = "main-workspace"
|
||||
KINTO_BUCKET_MAIN = "main"
|
||||
KINTO_COLLECTION = "messaging-experiments"
|
||||
KINTO_COLLECTION_NIMBUS_DESKTOP = "nimbus-desktop-experiments"
|
||||
KINTO_COLLECTION_NIMBUS_MOBILE = "nimbus-mobile-experiments"
|
||||
|
||||
|
||||
# Jetstream GCS Bucket data
|
||||
|
|
Загрузка…
Ссылка в новой задаче