Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backup): Enable shimming deleted fields #66248

Merged
merged 2 commits into from
Mar 4, 2024
Merged
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions src/sentry/backup/imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@
"import_in_global_scope",
)

# We have to be careful when removing fields from our model schemas, since exports created using
# the old-but-still-in-the-support-window versions could have those fields set in the data they
# provide. This dict serves as a map of all fields that have been deleted on HEAD but are still
# valid in at least one of the versions we support. For example, since our current version
# support window is two minor versions back, if we delete a field at version 24.5.N, we must
# include an entry in this map for that field until that version is out of the support window
# (in this case, we can remove shim once version 24.7.0 is released).
#
# NOTE TO FUTURE EDITORS: please keep the `DELETED_FIELDS` dict, and the subsequent `if` clause,
# around even if the dict is empty, to ensure that there is a ready place to pop shims into. For
# each entry in this dict, please leave a TODO comment pointed to a github issue for removing
# the shim, noting in the comment which self-hosted release will trigger the removal.
DELETED_FIELDS: dict[str, set[str]] = {}


class ImportingError(Exception):
def __init__(self, context: RpcImportError) -> None:
Expand Down Expand Up @@ -135,6 +149,21 @@ def _import(
if decryptor is not None
else src.read().decode("utf-8")
)

if len(DELETED_FIELDS) > 0:
# Parse the content JSON and remove and fields that we have marked for deletion in the
# function.
shimmed_models = set(DELETED_FIELDS.keys())
content_as_json = json.loads(content) # type: ignore
for json_model in content_as_json:
if json_model["model"] in shimmed_models:
fields_to_remove = DELETED_FIELDS[json_model["model"]]
for field in fields_to_remove:
json_model["fields"].pop(field, None)

# Return the content to byte form, as that is what the Django deserializer expects.
content = json.dumps(content_as_json)

filters = []
if filter_by is not None:
filters.append(filter_by)
Expand Down
Loading