From 02174a2cff345ac3ee5c07267cbfeb477b51c95e Mon Sep 17 00:00:00 2001 From: mcilwain Date: Wed, 9 Jan 2019 08:26:26 -0800 Subject: [PATCH] Delete applications even when index is missing This makes the deletion mapreduce more resilient in the face of data integrity violations (which exist on sandbox but hopefully not in production). Even when the domain application index doesn't exist, we still want to delete the domain application itself, as its continuing presence will cause problems after the code for domain applications is deleted. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=228521794 --- .../KillAllDomainApplicationsAction.java | 24 +++++++++++++++---- .../KillAllDomainApplicationsActionTest.java | 23 ++++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/java/google/registry/tools/server/KillAllDomainApplicationsAction.java b/java/google/registry/tools/server/KillAllDomainApplicationsAction.java index 8b639ba09..0c9673b20 100644 --- a/java/google/registry/tools/server/KillAllDomainApplicationsAction.java +++ b/java/google/registry/tools/server/KillAllDomainApplicationsAction.java @@ -75,20 +75,34 @@ public class KillAllDomainApplicationsAction implements Runnable { getContext().incrementCounter("applications already deleted"); return; } + Key applicationKey = Key.create(application); DomainApplicationIndex dai = ofy().load().key(DomainApplicationIndex.createKey(application)).now(); EppResourceIndex eri = ofy().load().entity(EppResourceIndex.create(applicationKey)).now(); - if (dai == null || eri == null) { + + if (dai == null) { logger.atSevere().log( - "Missing index(es) for application %s; skipping.", applicationKey); - getContext().incrementCounter("missing indexes"); - return; + "Missing domain application index for application %s.", applicationKey); + getContext().incrementCounter("missing domain application indexes"); + } else { + ofy().delete().entity(dai); } + + // This case shouldn't be possible except in extremely rare circumstances, as this + // mapreduce itself is relying on EPP resource indexes to load the domain + // applications to delete. + if (eri == null) { + logger.atSevere().log( + "Missing EPP resource index for application %s.", applicationKey); + getContext().incrementCounter("missing EPP resource indexes"); + } else { + ofy().delete().entity(eri); + } + // Delete the application, its descendents, and the indexes. ofy().delete().keys(ofy().load().ancestor(application).keys()); - ofy().delete().entities(dai, eri); logger.atInfo().log("Deleted domain application %s.", applicationKey); getContext().incrementCounter("applications deleted"); }); diff --git a/javatests/google/registry/tools/server/KillAllDomainApplicationsActionTest.java b/javatests/google/registry/tools/server/KillAllDomainApplicationsActionTest.java index 102df8adf..544457a0f 100644 --- a/javatests/google/registry/tools/server/KillAllDomainApplicationsActionTest.java +++ b/javatests/google/registry/tools/server/KillAllDomainApplicationsActionTest.java @@ -16,6 +16,7 @@ package google.registry.tools.server; import static com.google.common.truth.Truth.assertThat; import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.createTlds; import static google.registry.testing.DatastoreHelper.persistActiveContact; import static google.registry.testing.DatastoreHelper.persistActiveDomain; @@ -91,4 +92,26 @@ public class KillAllDomainApplicationsActionTest .entities(application, applicationEri, applicationDai, applicationHistoryEntry)) .isEmpty(); } + + @Test + public void test_deletesApplication_evenWhenIndexIsMissing() throws Exception { + createTld("tld1"); + DomainApplication application = persistActiveDomainApplication("applied.tld1"); + EppResourceIndex applicationEri = + ofy().load().entity(EppResourceIndex.create(Key.create(application))).now(); + HistoryEntry applicationHistoryEntry = + persistResource(new HistoryEntry.Builder().setParent(application).build()); + + // Delete the domain application index. + ofy().transact(() -> ofy().delete().key(DomainApplicationIndex.createKey(application)).now()); + ofy().clearSessionCache(); + + runMapreduce(); + ofy().clearSessionCache(); + + // Check that the domain application and history entry were deleted even though the indexes + // couldn't be found. + assertThat(ofy().load().entities(application, applicationEri, applicationHistoryEntry)) + .isEmpty(); + } }