mirror of
https://github.com/google/nomulus.git
synced 2025-07-19 17:26:09 +02:00
Add hoc tool to fix duplicate contactId (#1076)
* Add hoc tool to fix duplicate contactId
This commit is contained in:
parent
d35460f14c
commit
abe6a193a8
3 changed files with 120 additions and 0 deletions
|
@ -17,6 +17,7 @@ package google.registry.tools;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.tools.javascrap.BackfillRegistryLocksCommand;
|
||||
import google.registry.tools.javascrap.BackfillSpec11ThreatMatchesCommand;
|
||||
import google.registry.tools.javascrap.DeleteContactByRoidCommand;
|
||||
import google.registry.tools.javascrap.PopulateNullRegistrarFieldsCommand;
|
||||
import google.registry.tools.javascrap.RemoveIpAddressCommand;
|
||||
|
||||
|
@ -54,6 +55,7 @@ public final class RegistryTool {
|
|||
.put("dedupe_one_time_billing_event_ids", DedupeOneTimeBillingEventIdsCommand.class)
|
||||
.put("dedupe_recurring_billing_event_ids", DedupeRecurringBillingEventIdsCommand.class)
|
||||
.put("delete_allocation_tokens", DeleteAllocationTokensCommand.class)
|
||||
.put("delete_contact_by_roid", DeleteContactByRoidCommand.class)
|
||||
.put("delete_domain", DeleteDomainCommand.class)
|
||||
.put("delete_host", DeleteHostCommand.class)
|
||||
.put("delete_premium_list", DeletePremiumListCommand.class)
|
||||
|
|
|
@ -42,6 +42,7 @@ import google.registry.request.Modules.URLFetchServiceModule;
|
|||
import google.registry.request.Modules.UrlFetchTransportModule;
|
||||
import google.registry.request.Modules.UserServiceModule;
|
||||
import google.registry.tools.AuthModule.LocalCredentialModule;
|
||||
import google.registry.tools.javascrap.DeleteContactByRoidCommand;
|
||||
import google.registry.util.UtilsModule;
|
||||
import google.registry.whois.NonCachingWhoisModule;
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -104,6 +105,8 @@ interface RegistryToolComponent {
|
|||
|
||||
void inject(CreateTldCommand command);
|
||||
|
||||
void inject(DeleteContactByRoidCommand command);
|
||||
|
||||
void inject(DeployInvoicingPipelineCommand command);
|
||||
|
||||
void inject(DeploySpec11PipelineCommand command);
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2021 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.tools.javascrap;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.index.EppResourceIndex;
|
||||
import google.registry.model.index.ForeignKeyIndex;
|
||||
import google.registry.tools.CommandWithRemoteApi;
|
||||
import google.registry.tools.ConfirmingCommand;
|
||||
import google.registry.util.SystemClock;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Deletes a {@link google.registry.model.contact.ContactResource} by its ROID.
|
||||
*
|
||||
* <p>This is a short-term tool for race condition clean up while the bug is being fixed.
|
||||
*/
|
||||
@Parameters(separators = " =", commandDescription = "Delete a contact by its ROID.")
|
||||
public class DeleteContactByRoidCommand extends ConfirmingCommand implements CommandWithRemoteApi {
|
||||
|
||||
@Parameter(names = "--roid", description = "The roid of the contact to be deleted.")
|
||||
String roid;
|
||||
|
||||
@Parameter(
|
||||
names = "--contact_id",
|
||||
description = "The user provided contactId, for verification purpose.")
|
||||
String contactId;
|
||||
|
||||
ImmutableList<Key<?>> toDelete;
|
||||
|
||||
@Override
|
||||
protected void init() throws Exception {
|
||||
System.out.printf("Deleting %s, which refers to %s.\n", roid, contactId);
|
||||
tm().transact(
|
||||
() -> {
|
||||
Key<ContactResource> targetKey = Key.create(ContactResource.class, roid);
|
||||
ContactResource targetContact = ofy().load().key(targetKey).now();
|
||||
verify(
|
||||
Objects.equals(targetContact.getContactId(), contactId),
|
||||
"contactId does not match.");
|
||||
verify(
|
||||
Objects.equals(targetContact.getStatusValues(), ImmutableSet.of(StatusValue.OK)));
|
||||
System.out.println("Target contact has the expected contactId");
|
||||
String canonicalResource =
|
||||
ForeignKeyIndex.load(ContactResource.class, contactId, new SystemClock().nowUtc())
|
||||
.getResourceKey()
|
||||
.getOfyKey()
|
||||
.getName();
|
||||
verify(!Objects.equals(canonicalResource, roid), "Contact still in ForeignKeyIndex.");
|
||||
System.out.printf(
|
||||
"It is safe to delete %s, since the contactId is mapped to a different entry in"
|
||||
+ " the Foreign key index (%s).\n\n",
|
||||
roid, canonicalResource);
|
||||
|
||||
List<Object> ancestors =
|
||||
ofy().load().ancestor(Key.create(ContactResource.class, roid)).list();
|
||||
|
||||
System.out.println("Ancestor query returns: ");
|
||||
for (Object entity : ancestors) {
|
||||
System.out.println(Key.create(entity));
|
||||
}
|
||||
|
||||
ImmutableSet<String> deletetableKinds =
|
||||
ImmutableSet.of("HistoryEntry", "ContactResource");
|
||||
toDelete =
|
||||
ancestors.stream()
|
||||
.map(Key::create)
|
||||
.filter(key -> deletetableKinds.contains(key.getKind()))
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
|
||||
EppResourceIndex eppResourceIndex =
|
||||
ofy().load().entity(EppResourceIndex.create(targetKey)).now();
|
||||
verify(eppResourceIndex.getKey().equals(targetKey), "Wrong EppResource Index loaded");
|
||||
System.out.printf("\n\nEppResourceIndex found (%s).\n", Key.create(eppResourceIndex));
|
||||
|
||||
toDelete =
|
||||
new ImmutableList.Builder<Key<?>>()
|
||||
.addAll(toDelete)
|
||||
.add(Key.create(eppResourceIndex))
|
||||
.build();
|
||||
|
||||
System.out.printf("\n\nAbout to delete %s entities:\n", toDelete.size());
|
||||
toDelete.forEach(key -> System.out.println(key));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String execute() {
|
||||
tm().transact(() -> ofy().delete().keys(toDelete).now());
|
||||
return "Done";
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue