mirror of
https://github.com/google/nomulus
synced 2026-05-21 07:11:48 +00:00
Compare commits
4 Commits
nomulus-20
...
nomulus-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d18dab3327 | ||
|
|
61932c1809 | ||
|
|
8eb8c810e8 | ||
|
|
c03a7b0b33 |
@@ -102,6 +102,7 @@
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<!-- Disabled for sql-only tests.
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/commitLogCheckpoint]]></url>
|
||||
<description>
|
||||
@@ -110,6 +111,7 @@
|
||||
<schedule>every 3 minutes synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
-->
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/deleteContactsAndHosts]]></url>
|
||||
@@ -133,6 +135,7 @@
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<!-- Disabled for sql-only tests
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=export-snapshot&endpoint=/_dr/task/backupDatastore&runInEmpty]]></url>
|
||||
<description>
|
||||
@@ -142,14 +145,12 @@
|
||||
</description>
|
||||
<!--
|
||||
Keep google.registry.export.CheckBackupAction.MAXIMUM_BACKUP_RUNNING_TIME less than
|
||||
this interval. -->
|
||||
this interval. - ->
|
||||
<schedule>every day 06:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
-->
|
||||
|
||||
<!--
|
||||
Removed for the duration of load testing
|
||||
TODO(b/71607184): Restore after loadtesting is done
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<description>
|
||||
@@ -159,7 +160,6 @@
|
||||
<timezone>UTC</timezone>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
-->
|
||||
|
||||
<!-- TODO: Add borgmon job to check that these files are created and updated successfully. -->
|
||||
<cron>
|
||||
@@ -200,6 +200,7 @@
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<!-- Disabled for sql-only tests.
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=replay-commit-logs-to-sql&endpoint=/_dr/task/replayCommitLogsToSql&runInEmpty]]></url>
|
||||
<description>
|
||||
@@ -208,4 +209,26 @@
|
||||
<schedule>every 3 minutes</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
-->
|
||||
|
||||
<!--
|
||||
The next two wipeout jobs are required when crash has production data.
|
||||
-->
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/wipeOutCloudSql]]></url>
|
||||
<description>
|
||||
This job runs an action that deletes all data in Cloud SQL.
|
||||
</description>
|
||||
<schedule>every saturday 03:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/wipeOutDatastore]]></url>
|
||||
<description>
|
||||
This job runs an action that deletes all data in Cloud Datastore.
|
||||
</description>
|
||||
<schedule>every saturday 03:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
</cronentries>
|
||||
|
||||
@@ -43,7 +43,6 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.server.Lock;
|
||||
import google.registry.model.server.ServerSecret;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.model.tmch.ClaimsList;
|
||||
import google.registry.model.tmch.ClaimsList.ClaimsListRevision;
|
||||
import google.registry.model.tmch.ClaimsList.ClaimsListSingleton;
|
||||
@@ -92,7 +91,6 @@ public final class EntityClasses {
|
||||
Registrar.class,
|
||||
RegistrarContact.class,
|
||||
Registry.class,
|
||||
ReservedList.class,
|
||||
ServerSecret.class,
|
||||
TmchCrl.class);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public final class RdeNamingUtils {
|
||||
}
|
||||
|
||||
/** Returns same thing as {@link #makeRydeFilename} except without the series and revision. */
|
||||
static String makePartialName(String tld, DateTime date, RdeMode mode) {
|
||||
public static String makePartialName(String tld, DateTime date, RdeMode mode) {
|
||||
return String.format("%s_%s_%s",
|
||||
checkNotNull(tld), formatDate(date), mode.getFilenameComponent());
|
||||
}
|
||||
|
||||
@@ -33,13 +33,8 @@ import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Mapify;
|
||||
import com.googlecode.objectify.mapper.Mapper;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.replay.NonReplicatedEntity;
|
||||
import google.registry.model.replay.SqlOnlyEntity;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.label.DomainLabelMetrics.MetricsReservedListMatch;
|
||||
import java.io.Serializable;
|
||||
@@ -65,13 +60,11 @@ import org.joda.time.DateTime;
|
||||
* succeeds, we will end up with having two exact same reserved lists that differ only by
|
||||
* revisionId. This is fine though, because we only use the list with the highest revisionId.
|
||||
*/
|
||||
@Entity
|
||||
@ReportedOn
|
||||
@javax.persistence.Entity
|
||||
@Table(indexes = {@Index(columnList = "name", name = "reservedlist_name_idx")})
|
||||
public final class ReservedList
|
||||
extends BaseDomainLabelList<ReservationType, ReservedList.ReservedListEntry>
|
||||
implements NonReplicatedEntity {
|
||||
implements SqlOnlyEntity {
|
||||
|
||||
/**
|
||||
* Mapping from domain name to its reserved list info.
|
||||
@@ -80,7 +73,6 @@ public final class ReservedList
|
||||
* from the immutability contract so we can modify it after construction and we have to handle the
|
||||
* database processing on our own so we can detach it after load.
|
||||
*/
|
||||
@Mapify(ReservedListEntry.LabelMapper.class)
|
||||
@Insignificant
|
||||
@Transient
|
||||
Map<String, ReservedListEntry> reservedListMap;
|
||||
@@ -121,10 +113,9 @@ public final class ReservedList
|
||||
* A reserved list entry entity, persisted to Datastore, that represents a single label and its
|
||||
* reservation type.
|
||||
*/
|
||||
@Embed
|
||||
@javax.persistence.Entity(name = "ReservedEntry")
|
||||
public static class ReservedListEntry extends DomainLabelEntry<ReservationType, ReservedListEntry>
|
||||
implements Buildable, NonReplicatedEntity, Serializable {
|
||||
implements Buildable, SqlOnlyEntity, Serializable {
|
||||
|
||||
@Insignificant @Id Long revisionId;
|
||||
|
||||
@@ -133,15 +124,6 @@ public final class ReservedList
|
||||
|
||||
String comment;
|
||||
|
||||
/** Mapper for use with @Mapify */
|
||||
static class LabelMapper implements Mapper<String, ReservedListEntry> {
|
||||
|
||||
@Override
|
||||
public String getKey(ReservedListEntry entry) {
|
||||
return entry.getDomainLabel();
|
||||
}
|
||||
}
|
||||
|
||||
public String getComment(String comment) {
|
||||
return comment;
|
||||
}
|
||||
@@ -239,7 +221,7 @@ public final class ReservedList
|
||||
* @return An Optional<ReservedList> that has a value if a reserved list exists by the given
|
||||
* name, or absent if not.
|
||||
* @throws UncheckedExecutionException if some other error occurs while trying to load the
|
||||
* ReservedList from the cache or Datastore.
|
||||
* ReservedList from the cache or database.
|
||||
*/
|
||||
public static Optional<ReservedList> get(String listName) {
|
||||
return getFromCache(listName, cache);
|
||||
|
||||
@@ -31,7 +31,6 @@ import google.registry.request.RequestModule;
|
||||
import google.registry.request.RequestScope;
|
||||
import google.registry.tools.server.CreateGroupsAction;
|
||||
import google.registry.tools.server.CreatePremiumListAction;
|
||||
import google.registry.tools.server.DeleteEntityAction;
|
||||
import google.registry.tools.server.GenerateZoneFilesAction;
|
||||
import google.registry.tools.server.KillAllCommitLogsAction;
|
||||
import google.registry.tools.server.KillAllEppResourcesAction;
|
||||
@@ -63,7 +62,6 @@ import google.registry.tools.server.VerifyOteAction;
|
||||
interface ToolsRequestComponent {
|
||||
CreateGroupsAction createGroupsAction();
|
||||
CreatePremiumListAction createPremiumListAction();
|
||||
DeleteEntityAction deleteEntityAction();
|
||||
EppToolAction eppToolAction();
|
||||
FlowComponent.Builder flowComponentBuilder();
|
||||
GenerateZoneFilesAction generateZoneFilesAction();
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright 2020 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.persistence.converter;
|
||||
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
/** JPA converter for a set of {@link Key} containing a {@link ReservedList} */
|
||||
@Converter(autoApply = true)
|
||||
public class ReservedListKeySetConverter extends StringSetConverterBase<Key<ReservedList>> {
|
||||
|
||||
@Override
|
||||
String toString(Key<ReservedList> key) {
|
||||
return key.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
Key<ReservedList> fromString(String value) {
|
||||
return Key.create(getCrossTldKey(), ReservedList.class, value);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,8 @@ import javax.annotation.Nullable;
|
||||
* Base class for specification of command line parameters common to creating and updating reserved
|
||||
* lists.
|
||||
*/
|
||||
public abstract class CreateOrUpdateReservedListCommand extends MutatingCommand {
|
||||
public abstract class CreateOrUpdateReservedListCommand extends ConfirmingCommand
|
||||
implements CommandWithRemoteApi {
|
||||
|
||||
static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
|
||||
@@ -25,9 +25,7 @@ import com.beust.jcommander.Parameters;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -48,7 +46,7 @@ final class CreateReservedListCommand extends CreateOrUpdateReservedListCommand
|
||||
boolean override;
|
||||
|
||||
@Override
|
||||
protected void init() throws Exception {
|
||||
protected String prompt() throws Exception {
|
||||
name = Strings.isNullOrEmpty(name) ? convertFilePathToName(input) : name;
|
||||
checkArgument(
|
||||
!ReservedList.get(name).isPresent(), "A reserved list already exists by this name");
|
||||
@@ -66,35 +64,11 @@ final class CreateReservedListCommand extends CreateOrUpdateReservedListCommand
|
||||
.setCreationTimestamp(now)
|
||||
.build();
|
||||
|
||||
// calls the stageEntityChange method that takes old entity, new entity and a new vkey;
|
||||
// Because ReservedList is a sqlEntity and its primary key field (revisionId) is only set when
|
||||
// it's being persisted; a vkey has to be created here explicitly for ReservedList instances.
|
||||
stageEntityChange(
|
||||
null, reservedList, VKey.createOfy(ReservedList.class, Key.create(reservedList)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String prompt() {
|
||||
return getChangedEntities().isEmpty()
|
||||
? "No entity changes to apply."
|
||||
: getChangedEntities().stream()
|
||||
.map(
|
||||
entity -> {
|
||||
if (entity instanceof ReservedList) {
|
||||
// Format the entries of the reserved list as well.
|
||||
String entries =
|
||||
((ReservedList) entity)
|
||||
.getReservedListEntries().entrySet().stream()
|
||||
.map(
|
||||
entry ->
|
||||
String.format("%s=%s", entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.joining(", "));
|
||||
return String.format("%s\nreservedListMap={%s}\n", entity, entries);
|
||||
} else {
|
||||
return entity.toString();
|
||||
}
|
||||
})
|
||||
.collect(Collectors.joining("\n"));
|
||||
String entries =
|
||||
reservedList.getReservedListEntries().entrySet().stream()
|
||||
.map(entry -> String.format("%s=%s", entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.joining(", "));
|
||||
return String.format("%s\nreservedListMap={%s}\n", reservedList, entries);
|
||||
}
|
||||
|
||||
private static void validateListName(String name) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm;
|
||||
import static google.registry.tools.Injector.injectReflectively;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
@@ -244,7 +244,7 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
|
||||
ObjectifyService.initOfy();
|
||||
// Make sure we start the command with a clean cache, so that any previous command won't
|
||||
// interfere with this one.
|
||||
tm().clearSessionCache();
|
||||
ofyTm().clearSessionCache();
|
||||
|
||||
// Enable Cloud SQL for command that needs remote API as they will very likely use
|
||||
// Cloud SQL after the database migration. Note that the DB password is stored in Datastore
|
||||
|
||||
@@ -19,18 +19,17 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.base.Strings;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** Command to safely update {@link ReservedList}. */
|
||||
@Parameters(separators = " =", commandDescription = "Update a ReservedList.")
|
||||
final class UpdateReservedListCommand extends CreateOrUpdateReservedListCommand {
|
||||
|
||||
@Override
|
||||
protected void init() throws Exception {
|
||||
protected String prompt() throws Exception {
|
||||
name = Strings.isNullOrEmpty(name) ? convertFilePathToName(input) : name;
|
||||
ReservedList existingReservedList =
|
||||
ReservedList.get(name)
|
||||
@@ -53,15 +52,18 @@ final class UpdateReservedListCommand extends CreateOrUpdateReservedListCommand
|
||||
if (!existingReservedList
|
||||
.getReservedListEntries()
|
||||
.equals(reservedList.getReservedListEntries())) {
|
||||
// calls the stageEntityChange method that takes old entity, new entity and a new vkey;
|
||||
// a vkey has to be created here explicitly for ReservedList instances.
|
||||
// ReservedList is a sqlEntity; it triggers the static method Vkey.create(Key<?> ofyCall),
|
||||
// which invokes a static ReservedList.createVkey(Key ofyKey) method that does not exist.
|
||||
// the sql primary key field (revisionId) is only set when it's being persisted;
|
||||
stageEntityChange(
|
||||
existingReservedList,
|
||||
reservedList,
|
||||
VKey.createOfy(ReservedList.class, Key.create(existingReservedList)));
|
||||
String oldEntries =
|
||||
existingReservedList.getReservedListEntries().entrySet().stream()
|
||||
.map(entry -> String.format("%s=%s", entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.joining(", "));
|
||||
String newEntries =
|
||||
reservedList.getReservedListEntries().entrySet().stream()
|
||||
.map(entry -> String.format("%s=%s", entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.joining(", "));
|
||||
return String.format(
|
||||
"Update reserved list for %s?\nOld List: %s\n New List: %s",
|
||||
name, oldEntries, newEntries);
|
||||
}
|
||||
return "No entity changes to apply.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
// Copyright 2017 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.server;
|
||||
|
||||
import static com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService;
|
||||
import static com.googlecode.objectify.Key.create;
|
||||
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.google.appengine.api.datastore.Entity;
|
||||
import com.google.appengine.api.datastore.EntityNotFoundException;
|
||||
import com.google.appengine.api.datastore.Key;
|
||||
import com.google.appengine.api.datastore.KeyFactory;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.googlecode.objectify.impl.EntityMetadata;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* An action to delete entities in Datastore specified by raw key ids, which can be found in
|
||||
* Datastore Viewer in the AppEngine console - it's the really long alphanumeric key that is labeled
|
||||
* "Entity key" on the page for an individual entity.
|
||||
*
|
||||
* <p>rawKeys is the only required parameter. It is a comma-delimited list of Strings.
|
||||
*
|
||||
* <p><b>WARNING:</b> This servlet can be dangerous if used incorrectly as it can bypass checks on
|
||||
* deletion (including whether the entity is referenced by other entities) and it does not write
|
||||
* commit log entries for non-registered types. It should mainly be used for deleting testing or
|
||||
* malformed data that cannot be properly deleted using existing tools. Generally, if there already
|
||||
* exists an entity-specific deletion command, then use that one instead.
|
||||
*/
|
||||
@Action(
|
||||
service = Action.Service.TOOLS,
|
||||
path = DeleteEntityAction.PATH,
|
||||
auth = Auth.AUTH_INTERNAL_OR_ADMIN)
|
||||
public class DeleteEntityAction implements Runnable {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
public static final String PATH = "/_dr/admin/deleteEntity";
|
||||
public static final String PARAM_RAW_KEYS = "rawKeys";
|
||||
|
||||
private final String rawKeys;
|
||||
private final Response response;
|
||||
|
||||
@Inject
|
||||
DeleteEntityAction(@Parameter(PARAM_RAW_KEYS) String rawKeys, Response response) {
|
||||
this.rawKeys = rawKeys;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Get raw key strings from request
|
||||
ImmutableList.Builder<Object> ofyDeletionsBuilder = new ImmutableList.Builder<>();
|
||||
ImmutableList.Builder<Key> rawDeletionsBuilder = new ImmutableList.Builder<>();
|
||||
for (String rawKeyString : Splitter.on(',').split(rawKeys)) {
|
||||
// Convert raw keys string to real keys. Try to load it from Objectify if it's a registered
|
||||
// type, and fall back to DatastoreService if its not registered.
|
||||
Key rawKey = KeyFactory.stringToKey(rawKeyString);
|
||||
Optional<Object> ofyEntity = loadOfyEntity(rawKey);
|
||||
if (ofyEntity.isPresent()) {
|
||||
ofyDeletionsBuilder.add(ofyEntity.get());
|
||||
continue;
|
||||
}
|
||||
Optional<Entity> rawEntity = loadRawEntity(rawKey);
|
||||
if (rawEntity.isPresent()) {
|
||||
rawDeletionsBuilder.add(rawEntity.get().getKey());
|
||||
continue;
|
||||
}
|
||||
// The entity could not be found by either Objectify or the Datastore service
|
||||
throw new BadRequestException("Could not find entity with key " + rawKeyString);
|
||||
}
|
||||
// Delete raw entities.
|
||||
ImmutableList<Key> rawDeletions = rawDeletionsBuilder.build();
|
||||
getDatastoreService().delete(rawDeletions);
|
||||
// Delete ofy entities.
|
||||
final ImmutableList<Object> ofyDeletions = ofyDeletionsBuilder.build();
|
||||
tm().transactNew(() -> auditedOfy().delete().entities(ofyDeletions).now());
|
||||
String message = String.format(
|
||||
"Deleted %d raw entities and %d registered entities",
|
||||
rawDeletions.size(),
|
||||
ofyDeletions.size());
|
||||
logger.atInfo().log(message);
|
||||
response.setPayload(message);
|
||||
}
|
||||
|
||||
private Optional<Object> loadOfyEntity(Key rawKey) {
|
||||
try {
|
||||
EntityMetadata<Object> metadata = auditedOfy().factory().getMetadata(rawKey.getKind());
|
||||
return Optional.ofNullable(
|
||||
metadata == null ? null : auditedOfy().load().key(create(rawKey)).now());
|
||||
} catch (Throwable e) {
|
||||
logger.atWarning().withCause(e).log(
|
||||
"Could not load entity with key %s using Objectify; falling back to raw Datastore.",
|
||||
rawKey);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Entity> loadRawEntity(Key rawKey) {
|
||||
try {
|
||||
return Optional.ofNullable(getDatastoreService().get(rawKey));
|
||||
} catch (EntityNotFoundException e) {
|
||||
logger.atWarning().withCause(e).log(
|
||||
"Could not load entity from Datastore service with key %s", rawKey);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,6 @@
|
||||
<class>google.registry.persistence.converter.LocalDateConverter</class>
|
||||
<class>google.registry.persistence.converter.PostalInfoChoiceListConverter</class>
|
||||
<class>google.registry.persistence.converter.RegistrarPocSetConverter</class>
|
||||
<class>google.registry.persistence.converter.ReservedListKeySetConverter</class>
|
||||
<class>google.registry.persistence.converter.Spec11ThreatMatchThreatTypeSetConverter</class>
|
||||
<class>google.registry.persistence.converter.StatusValueSetConverter</class>
|
||||
<class>google.registry.persistence.converter.StringListConverter</class>
|
||||
|
||||
@@ -38,7 +38,6 @@ import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.cloud.storage.contrib.nio.testing.LocalStorageHelper;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.truth.Truth8;
|
||||
@@ -55,12 +54,14 @@ import google.registry.model.index.ForeignKeyIndex;
|
||||
import google.registry.model.ofy.CommitLogBucket;
|
||||
import google.registry.model.ofy.CommitLogManifest;
|
||||
import google.registry.model.ofy.CommitLogMutation;
|
||||
import google.registry.model.rde.RdeMode;
|
||||
import google.registry.model.rde.RdeNamingUtils;
|
||||
import google.registry.model.rde.RdeRevision;
|
||||
import google.registry.model.registrar.RegistrarContact;
|
||||
import google.registry.model.replay.SqlReplayCheckpoint;
|
||||
import google.registry.model.server.Lock;
|
||||
import google.registry.model.tld.label.PremiumList;
|
||||
import google.registry.model.tld.label.PremiumList.PremiumEntry;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.model.tmch.ClaimsList;
|
||||
import google.registry.model.translators.VKeyTranslatorFactory;
|
||||
import google.registry.persistence.VKey;
|
||||
@@ -419,8 +420,9 @@ public class ReplayCommitLogsToSqlActionTest {
|
||||
|
||||
createTld("tld");
|
||||
// Have a commit log with a couple objects that shouldn't be replayed
|
||||
ReservedList reservedList =
|
||||
new ReservedList.Builder().setReservedListMap(ImmutableMap.of()).setName("name").build();
|
||||
String triplet = RdeNamingUtils.makePartialName("tld", fakeClock.nowUtc(), RdeMode.FULL);
|
||||
RdeRevision rdeRevision =
|
||||
RdeRevision.create(triplet, "tld", fakeClock.nowUtc().toLocalDate(), RdeMode.FULL, 1);
|
||||
ForeignKeyIndex<DomainBase> fki = ForeignKeyIndex.create(newDomainBase("foo.tld"), now);
|
||||
tm().transact(
|
||||
() -> {
|
||||
@@ -430,8 +432,8 @@ public class ReplayCommitLogsToSqlActionTest {
|
||||
createCheckpoint(now.minusMinutes(1)),
|
||||
CommitLogManifest.create(
|
||||
getBucketKey(1), now.minusMinutes(1), ImmutableSet.of()),
|
||||
// Reserved list is dually-written non-replicated
|
||||
CommitLogMutation.create(manifestKey, reservedList),
|
||||
// RDE Revisions are not replicated
|
||||
CommitLogMutation.create(manifestKey, rdeRevision),
|
||||
// FKIs aren't replayed to SQL at all
|
||||
CommitLogMutation.create(manifestKey, fki));
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -33,15 +33,11 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.label.PremiumList.PremiumEntry;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectExtension;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@@ -50,19 +46,9 @@ class ReservedListTest {
|
||||
|
||||
private FakeClock clock = new FakeClock(DateTime.parse("2010-01-01T10:00:00Z"));
|
||||
|
||||
@Order(value = Order.DEFAULT - 1)
|
||||
@RegisterExtension
|
||||
final InjectExtension inject =
|
||||
new InjectExtension().withStaticFieldOverride(Ofy.class, "clock", clock);
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder()
|
||||
.withClock(clock)
|
||||
.withJpaUnitTestEntities(
|
||||
PremiumList.class, PremiumEntry.class, ReservedList.class, ReservedListEntry.class)
|
||||
.withDatastoreAndCloudSql()
|
||||
.build();
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withClock(clock).withCloudSql().build();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
// Copyright 2020 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.persistence.converter;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.testcontainers.shaded.com.google.common.collect.ImmutableSet;
|
||||
|
||||
/** Unit tests for {@link ReservedListKeySetConverter}. */
|
||||
class ReservedListKeySetConverterTest {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withJpaUnitTestEntities(ReservedListSetEntity.class)
|
||||
.build();
|
||||
|
||||
@Test
|
||||
void roundTripConversion_returnsSameSet() {
|
||||
Key<ReservedList> key1 = Key.create(getCrossTldKey(), ReservedList.class, "test1");
|
||||
Key<ReservedList> key2 = Key.create(getCrossTldKey(), ReservedList.class, "test2");
|
||||
Key<ReservedList> key3 = Key.create(getCrossTldKey(), ReservedList.class, "test3");
|
||||
|
||||
Set<Key<ReservedList>> reservedLists = ImmutableSet.of(key1, key2, key3);
|
||||
ReservedListSetEntity testEntity = new ReservedListSetEntity(reservedLists);
|
||||
jpaTm().transact(() -> jpaTm().insert(testEntity));
|
||||
ReservedListSetEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(ReservedListSetEntity.class, "id"));
|
||||
assertThat(persisted.reservedList).containsExactly(key1, key2, key3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullValue_writesAndReadsNullSuccessfully() {
|
||||
ReservedListSetEntity testEntity = new ReservedListSetEntity(null);
|
||||
jpaTm().transact(() -> jpaTm().insert(testEntity));
|
||||
ReservedListSetEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(ReservedListSetEntity.class, "id"));
|
||||
assertThat(persisted.reservedList).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmptyCollection_writesAndReadsEmptyCollectionSuccessfully() {
|
||||
ReservedListSetEntity testEntity = new ReservedListSetEntity(ImmutableSet.of());
|
||||
jpaTm().transact(() -> jpaTm().insert(testEntity));
|
||||
ReservedListSetEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(ReservedListSetEntity.class, "id"));
|
||||
assertThat(persisted.reservedList).isEmpty();
|
||||
}
|
||||
|
||||
@Entity(name = "ReservedListSetEntity")
|
||||
private static class ReservedListSetEntity extends ImmutableObject {
|
||||
|
||||
@Id String name = "id";
|
||||
|
||||
Set<Key<ReservedList>> reservedList;
|
||||
|
||||
public ReservedListSetEntity() {}
|
||||
|
||||
ReservedListSetEntity(Set<Key<ReservedList>> reservedList) {
|
||||
this.reservedList = reservedList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,6 +161,6 @@ class UpdateReservedListCommandTest
|
||||
command.input = Paths.get(reservedTermsPath);
|
||||
command.init();
|
||||
|
||||
assertThat(command.prompt()).contains("Update ReservedList@xn--q9jyb4c_common-reserved");
|
||||
assertThat(command.prompt()).contains("Update reserved list for xn--q9jyb4c_common-reserved?");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
// Copyright 2017 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.server;
|
||||
|
||||
import static com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.googlecode.objectify.Key.create;
|
||||
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.appengine.api.datastore.Entity;
|
||||
import com.google.appengine.api.datastore.KeyFactory;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link DeleteEntityAction}. */
|
||||
class DeleteEntityActionTest {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withDatastoreAndCloudSql().build();
|
||||
|
||||
private FakeResponse response = new FakeResponse();
|
||||
|
||||
@Test
|
||||
void test_deleteSingleRawEntitySuccessfully() {
|
||||
Entity entity = new Entity("single", "raw");
|
||||
getDatastoreService().put(entity);
|
||||
new DeleteEntityAction(KeyFactory.keyToString(entity.getKey()), response).run();
|
||||
assertThat(response.getPayload()).isEqualTo("Deleted 1 raw entities and 0 registered entities");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_deleteSingleRegisteredEntitySuccessfully() {
|
||||
ReservedList ofyEntity = new ReservedList.Builder().setName("foo").build();
|
||||
auditedOfy().saveWithoutBackup().entity(ofyEntity).now();
|
||||
new DeleteEntityAction(KeyFactory.keyToString(create(ofyEntity).getRaw()), response).run();
|
||||
assertThat(response.getPayload()).isEqualTo("Deleted 0 raw entities and 1 registered entities");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_deletePolymorphicEntity_fallbackSucceedsForUnregisteredType() {
|
||||
Entity entity = new Entity("single", "raw");
|
||||
entity.setIndexedProperty("^d", "UnregType");
|
||||
getDatastoreService().put(entity);
|
||||
new DeleteEntityAction(KeyFactory.keyToString(entity.getKey()), response).run();
|
||||
assertThat(response.getPayload()).isEqualTo("Deleted 1 raw entities and 0 registered entities");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_deleteOneRawEntityAndOneRegisteredEntitySuccessfully() {
|
||||
Entity entity = new Entity("first", "raw");
|
||||
getDatastoreService().put(entity);
|
||||
String rawKey = KeyFactory.keyToString(entity.getKey());
|
||||
ReservedList ofyEntity = new ReservedList.Builder().setName("registered").build();
|
||||
auditedOfy().saveWithoutBackup().entity(ofyEntity).now();
|
||||
String ofyKey = KeyFactory.keyToString(create(ofyEntity).getRaw());
|
||||
new DeleteEntityAction(String.format("%s,%s", rawKey, ofyKey), response).run();
|
||||
assertThat(response.getPayload()).isEqualTo("Deleted 1 raw entities and 1 registered entities");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_deleteNonExistentEntityRepliesWithError() {
|
||||
Entity entity = new Entity("not", "here");
|
||||
String rawKey = KeyFactory.keyToString(entity.getKey());
|
||||
BadRequestException thrown =
|
||||
assertThrows(
|
||||
BadRequestException.class, () -> new DeleteEntityAction(rawKey, response).run());
|
||||
assertThat(thrown).hasMessageThat().contains("Could not find entity with key " + rawKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_deleteOneEntityAndNonExistentEntityRepliesWithError() {
|
||||
ReservedList ofyEntity = new ReservedList.Builder().setName("first_registered").build();
|
||||
auditedOfy().saveWithoutBackup().entity(ofyEntity).now();
|
||||
String ofyKey = KeyFactory.keyToString(create(ofyEntity).getRaw());
|
||||
String rawKey = KeyFactory.keyToString(new Entity("non", "existent").getKey());
|
||||
BadRequestException thrown =
|
||||
assertThrows(
|
||||
BadRequestException.class,
|
||||
() -> new DeleteEntityAction(String.format("%s,%s", ofyKey, rawKey), response).run());
|
||||
assertThat(thrown).hasMessageThat().contains("Could not find entity with key " + rawKey);
|
||||
}
|
||||
}
|
||||
@@ -19,4 +19,3 @@ Recurring
|
||||
Registrar
|
||||
RegistrarContact
|
||||
Registry
|
||||
ReservedList
|
||||
|
||||
@@ -4,6 +4,5 @@ Cursor
|
||||
Registrar
|
||||
RegistrarContact
|
||||
Registry
|
||||
ReservedList
|
||||
ServerSecret
|
||||
TmchCrl
|
||||
|
||||
@@ -15,4 +15,3 @@ Recurring
|
||||
Registrar
|
||||
RegistrarContact
|
||||
Registry
|
||||
ReservedList
|
||||
|
||||
@@ -789,26 +789,6 @@ enum google.registry.model.tld.Registry$TldType {
|
||||
REAL;
|
||||
TEST;
|
||||
}
|
||||
enum google.registry.model.tld.label.ReservationType {
|
||||
ALLOWED_IN_SUNRISE;
|
||||
FULLY_BLOCKED;
|
||||
NAME_COLLISION;
|
||||
RESERVED_FOR_ANCHOR_TENANT;
|
||||
RESERVED_FOR_SPECIFIC_USE;
|
||||
}
|
||||
class google.registry.model.tld.label.ReservedList {
|
||||
@Id java.lang.String name;
|
||||
@Parent com.googlecode.objectify.Key<google.registry.model.common.EntityGroupRoot> parent;
|
||||
boolean shouldPublish;
|
||||
java.util.Map<java.lang.String, google.registry.model.tld.label.ReservedList$ReservedListEntry> reservedListMap;
|
||||
org.joda.time.DateTime creationTimestamp;
|
||||
}
|
||||
class google.registry.model.tld.label.ReservedList$ReservedListEntry {
|
||||
@Id java.lang.String domainLabel;
|
||||
google.registry.model.tld.label.ReservationType reservationType;
|
||||
java.lang.Long revisionId;
|
||||
java.lang.String comment;
|
||||
}
|
||||
class google.registry.model.tmch.ClaimsList {
|
||||
@Id long id;
|
||||
@Parent com.googlecode.objectify.Key<google.registry.model.tmch.ClaimsList$ClaimsListRevision> parent;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
PATH CLASS METHODS OK AUTH_METHODS MIN USER_POLICY
|
||||
/_dr/admin/createGroups CreateGroupsAction POST n INTERNAL,API APP ADMIN
|
||||
/_dr/admin/createPremiumList CreatePremiumListAction POST n INTERNAL,API APP ADMIN
|
||||
/_dr/admin/deleteEntity DeleteEntityAction GET n INTERNAL,API APP ADMIN
|
||||
/_dr/admin/list/domains ListDomainsAction GET,POST n INTERNAL,API APP ADMIN
|
||||
/_dr/admin/list/hosts ListHostsAction GET,POST n INTERNAL,API APP ADMIN
|
||||
/_dr/admin/list/premiumLists ListPremiumListsAction GET,POST n INTERNAL,API APP ADMIN
|
||||
|
||||
Reference in New Issue
Block a user