Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
b7dbe40
Initial plan
Copilot Nov 28, 2025
6bc79ec
Replace pycassa with cassandra ORM in cassie.py and add missing models
Copilot Nov 28, 2025
5106090
Address code review feedback: fix imports, simplify sorting, improve …
Copilot Nov 28, 2025
b91a175
Fix get_as_dict methods to be classmethods with proper cls parameter
Copilot Nov 28, 2025
595a083
Fix type handling in get_package_new_buckets for Ascii/Text fields
Copilot Nov 28, 2025
af139f4
Improve readability in record_bug_for_bucket by simplifying column1 e…
Copilot Nov 28, 2025
80cfb03
Fix dictionary-style access to use dot notation in get_as_dict methods
Copilot Nov 28, 2025
8c82f31
Add example scripts for all migrated cassie.py functions
Copilot Nov 28, 2025
098e692
Add setup_cassandra() call to all example scripts for easier use
Copilot Nov 28, 2025
64db2b2
cassie: don't call 'cassandra_session' at module import time
Hyask Dec 2, 2025
3edd52d
daisy: remove the counter updates
Hyask Dec 17, 2025
303536c
errortracker: fix cassandra schema
Hyask Dec 2, 2025
934bfc5
cassie: formatting pass
Hyask Dec 2, 2025
57f06cf
cassie: remove the use of OrderedDict, dict are ordered by default now
Hyask Dec 2, 2025
fc32293
oopses: try to make use of the 'Date' field of a crash
Hyask Dec 19, 2025
e813a7d
examples: default to using Noble, for more up-to-date data
Hyask Dec 2, 2025
46471c3
cassandra_schema: document columns
Hyask Dec 19, 2025
6d7dd08
cassie: manual tests and fixes against production data
Hyask Dec 19, 2025
a4d7452
tests: introduce testing of cassie
Hyask Dec 19, 2025
08f8184
Add comprehensive tests for get_package_crash_rate covering different…
Copilot Dec 17, 2025
3327564
tests: speed up tests by having cassandra fixtures be 'class' scoped
Hyask Dec 19, 2025
4826faa
tests: make a standalone 'create_test_data' script that can be called…
Hyask Jan 19, 2026
db717c6
cassie: add two tests for 'bucket_exists'
Hyask Jan 21, 2026
ca98f17
Add tests for get_crashes_for_bucket function
Copilot Jan 21, 2026
7939476
Add tests for get_metadata_for_bucket function
Copilot Jan 21, 2026
d5fc72c
Add tests for get_versions_for_bucket function
Copilot Jan 21, 2026
f12709f
Add tests for record_bug_for_bucket and get_signatures_for_bug functions
Copilot Jan 21, 2026
8da7878
tests: make 'test_get_metadata_for_bucket' actually relevant
Hyask Jan 21, 2026
567f3fb
cassie: fix get_versions_for_bucket and make its test useful
Hyask Jan 21, 2026
4267c71
README: add some notes around Cassandra
Hyask Jan 21, 2026
b6fb36b
Add tests for get_crash function
Copilot Jan 22, 2026
053eb82
Add tests for get_package_for_bucket function
Copilot Jan 22, 2026
fa38a5e
Add tests for get_problem_for_hash function
Copilot Jan 22, 2026
b16ff2c
Add tests for get_system_image_versions function
Copilot Jan 22, 2026
4353ec3
oopses: make sure to correctly parse the datetime, including correct …
Hyask Jan 22, 2026
5a3275e
oopses: keep ErrorsByRelease up to date
Hyask Jan 22, 2026
a63922c
oopses: fix potential bug, thanks to the linters
Hyask Jan 22, 2026
ba414de
tools: port remove_old_release_data to modern API
Hyask Jan 22, 2026
6ce3906
tests/cassie: make Copilot's tests useful
Hyask Jan 22, 2026
1627ca4
Add tests for get_source_package_for_bucket function
Copilot Jan 22, 2026
759d013
Add tests for get_traceback_for_bucket function
Copilot Jan 22, 2026
06c3695
Add tests for get_stacktrace_for_bucket function
Copilot Jan 22, 2026
4c24ef2
Add tests for get_retrace_failure_for_bucket function
Copilot Jan 22, 2026
1ae9fff
Add Traceback field to test data and update test_get_traceback_for_bu…
Copilot Jan 22, 2026
e671fff
Add specific value checks for thread_stacktrace in test_get_stacktrac…
Copilot Jan 22, 2026
de7c3f2
Add failed-retrace test data and update test_get_retrace_failure_for_…
Copilot Jan 22, 2026
9629ebc
tools/unique_users_daily_update: make that tool callable from the tests
Hyask Jan 23, 2026
c828f5f
tests: improve test data
Hyask Jan 22, 2026
20772b8
tests: cassie: fix test_get_traceback_for_bucket after Copilot handed…
Hyask Jan 22, 2026
e84296d
Add tests for get_metadata_for_buckets function
Copilot Jan 22, 2026
e81da7f
Add tests for get_user_crashes function
Copilot Jan 22, 2026
7682f58
Add tests for get_binary_packages_for_user function
Copilot Jan 22, 2026
5e14e6f
Add tests for get_package_new_buckets function
Copilot Jan 22, 2026
1284c33
Add tests for get_oopses_by_day function with specific value assertions
Copilot Jan 22, 2026
1ca956d
Add tests for get_oopses_by_release function with specific value asse…
Copilot Jan 22, 2026
77cd885
Add tests for get_total_buckets_by_day function with specific value a…
Copilot Jan 22, 2026
a4341c5
Add tests for get_bucket_counts function with specific value assertions
Copilot Jan 22, 2026
8b7e444
Add tests for get_retracer_count function with specific value assertions
Copilot Jan 22, 2026
afb800c
cassie: fix datetime API usage
Hyask Jan 23, 2026
db2c40b
oopses: fix how 'bucket' gets its 'day_key'
Hyask Jan 23, 2026
9f969bc
cassie: many more fixes, thanks to the tests
Hyask Jan 23, 2026
8d2c9fd
tests: cassie: make the rest of the Copilot tests useful
Hyask Jan 23, 2026
5ec4495
errors: we run Python 3 now
Hyask Jan 23, 2026
3a84012
Big ruff check pass
Hyask Jan 23, 2026
a7d16e5
Remove 'examples', they have served their purpose
Hyask Jan 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,18 @@ sudo apt install apport-retrace python3-amqp python3-bson python3-cassandra pyth
sudo apt install python3-django-tastypie python3-numpy
```

Then start a local Cassandra, RabbitMQ and swift (`docker` should works fine too):
Then start a local Cassandra, RabbitMQ and swift (`docker` should work fine too):
```
podman run --name cassandra --network host --rm -d -e HEAP_NEWSIZE=10M -e MAX_HEAP_SIZE=200M docker.io/cassandra
podman run --name rabbitmq --network host --rm -d docker.io/rabbitmq
podman run --name swift --network host --rm -d docker.io/openstackswift/saio
```

> Note:
> * Cassandra can take some time (a minute or two?) to fully start.
> * Also, sometimes, Cassandra can hang and you get some `OperationTimedOut`
> issues out of nowhere. Just `podman kill cassandra` and restart it.

You can then then run the tests with `pytest`:
```
cd src
Expand Down
55 changes: 4 additions & 51 deletions src/daisy/submit.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,6 @@
logger = logging.getLogger("daisy")


def update_counters(release, src_package, date, src_version=None):
if src_version:
key = "%s:%s:%s" % (release, src_package, src_version)
else:
key = "%s:%s" % (release, src_package)
cassandra_schema.Counters(key=key.encode(), column1=date).update(value=1)


def update_proposed_counters(release, src_package, date, src_version=None):
if src_version:
key = "%s:%s:%s" % (release, src_package, src_version)
else:
key = "%s:%s" % (release, src_package)
cassandra_schema.CountersForProposed(key=key.encode(), column1=date).update(value=1)


def create_minimal_report_from_bson(data):
report = Report()
for key in data:
Expand Down Expand Up @@ -181,12 +165,6 @@ def submit(request, system_token):
pkg_arch = utils.get_package_architecture(data)
problem_type = data.get("ProblemType", "")
apport_version = data.get("ApportVersion", "")
third_party = False
if not utils.retraceable_package(package):
third_party = True
automated_testing = False
if system_token.startswith("deadbeef"):
automated_testing = True

if not release:
metrics.meter("missing.missing_release")
Expand Down Expand Up @@ -221,21 +199,6 @@ def submit(request, system_token):
problem_type, release, package, version, pkg_arch
)

# generic counter for crashes about a source package which is used by the
# phased-updater and only includes official Ubuntu packages and not those
# crahses from systems under auto testing.
if not third_party and not automated_testing and problem_type == "Crash":
update_counters(release=release, src_package=src_package, date=day_key)
if version == "":
metrics.meter("missing.missing_package_version")
else:
update_counters(
release=release,
src_package=src_package,
src_version=version,
date=day_key,
)

# ProcMaps is useful for creating a crash sig, not after that
if "Traceback" in data and "ProcMaps" in data:
data.pop("ProcMaps")
Expand All @@ -262,18 +225,6 @@ def submit(request, system_token):
package_from_proposed = False
if "package-from-proposed" in tags:
package_from_proposed = True
# generic counter for crashes about a source package which is used by
# the phased-updater and only includes official Ubuntu packages and
# not those from systems under auto testing.
if not third_party and not automated_testing and problem_type == "Crash":
update_proposed_counters(release=release, src_package=src_package, date=day_key)
if version != "":
update_proposed_counters(
release=release,
src_package=src_package,
src_version=version,
date=day_key,
)

# A device is manually blocklisted if it has repeatedly failed to have an
# crash inserted into the OOPS table.
Expand Down Expand Up @@ -356,7 +307,7 @@ def bucket(oops_id, data, day_key):
key=b"crash_signature_for_stacktrace_address_signature", column1=addr_sig
).value.decode()
except DoesNotExist:
pass
metrics.meter("missing.crash_signature")
failed_to_retrace = False
if crash_sig.startswith("failed:"):
failed_to_retrace = True
Expand Down Expand Up @@ -401,7 +352,9 @@ def bucket(oops_id, data, day_key):
"StacktraceTop",
)
for unneeded_column in unneeded_columns:
cassandra_schema.OOPS.filter(key=oops_id.encode(), column1=unneeded_column).delete()
cassandra_schema.OOPS.filter(
key=oops_id.encode(), column1=unneeded_column
).delete()
# We have already retraced for this address signature, so this
# crash can be immediately bucketed.
utils.bucket(oops_id, crash_sig, data)
Expand Down
31 changes: 9 additions & 22 deletions src/errors/api/resources.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,23 @@
# Treat strings as UTF-8 instead of ASCII
import importlib
import sys
from functools import cmp_to_key

importlib.reload(sys)

from tastypie import fields
from tastypie.authentication import Authentication, SessionAuthentication
from tastypie.authorization import Authorization, DjangoAuthorization
from tastypie.exceptions import NotFound
from tastypie.resources import Resource

from errors import cassie

TASTYPIE_FULL_DEBUG = True

import datetime
import json as simplejson
from collections import OrderedDict
from functools import cmp_to_key
from hashlib import sha1
from operator import itemgetter
from urllib.error import HTTPError
from urllib.parse import quote, unquote

import apt
from django.core.serializers import json
from tastypie import fields
from tastypie.authentication import Authentication, SessionAuthentication
from tastypie.authorization import Authorization, DjangoAuthorization
from tastypie.exceptions import NotFound
from tastypie.resources import Resource
from tastypie.serializers import Serializer

from errors import cassie
from errortracker import config, launchpad

from ..metrics import measure_view
Expand Down Expand Up @@ -313,7 +304,7 @@ def obj_get(self, **kwargs):
oopses_by_day = set()
oopses_by_release = set()
for oops in cassie.get_oopses_by_day(date, limit):
oopses_by_day.add(str(oops))
oopses_by_day.add(oops)
oopses = oopses_by_day

if release:
Expand Down Expand Up @@ -614,10 +605,6 @@ def __getslice__(klass, start, finish):
# TODO: use a cassandra function that does a multiget of the
# crashes
for crash, ts in crashes:
# cassandra records time in microseconds, convert to
# seconds
ts = (ts["submitted"][1]) * 1e-6
ts = datetime.datetime.utcfromtimestamp(ts)
d = cassie.get_crash(str(crash), columns=cols)
program = split_package_and_version(d.get("Package", ""))[0]
if not program:
Expand Down Expand Up @@ -807,7 +794,7 @@ def __getslice__(klass, start, finish):
if item[0] in results:
results[item[0]] -= item[1]
results = sorted(
list(results.items()), key=cmp_to_key(lambda x, y: cmp(x[0], y[0]))
list(results.items()), key=cmp_to_key(lambda x, y: x[0] <= y[0])
)

res = [{"x": result[0] * 1000, "y": result[1]} for result in results]
Expand Down
4 changes: 2 additions & 2 deletions src/errors/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
def can_see_stacktraces(func):
def in_groups(u):
return u.groups.filter(name__in=groups).count() > 0
l = "/login-failed"
return login_required(user_passes_test(in_groups, login_url=l)(func))

return login_required(user_passes_test(in_groups, login_url="/login-failed")(func))
Loading
Loading