mirror of
https://github.com/google/nomulus
synced 2026-06-09 16:33:02 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b6083e227f | |||
| 5805b6859e | |||
| 3108e8a871 | |||
| ec142caf9c | |||
| e60ad58098 | |||
| 83e9e7fb5c | |||
| 438c523fcb | |||
| 025a2faff2 | |||
| fd822dd333 | |||
| 9b93749d43 | |||
| 71a8579ece | |||
| cda51f13dc | |||
| 1de5b5dcc1 | |||
| 32279e42e4 | |||
| ba0f90bdaf | |||
| 85308eb975 | |||
| ed62f27a4a | |||
| 75851399ba | |||
| 6d54c8d113 | |||
| 34dfa2760e | |||
| ff39a4a763 |
@@ -270,6 +270,10 @@
|
||||
"moduleLicense": "Public Domain",
|
||||
"moduleName": "org.tukaani:xz"
|
||||
},
|
||||
{
|
||||
"moduleLicense": "Public Domain",
|
||||
"moduleName": "org.json:json"
|
||||
},
|
||||
{
|
||||
// "Apache License, Version 2.0".
|
||||
"moduleLicense": null,
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
@@ -86,6 +85,6 @@ public final class AsyncTaskEnqueuer {
|
||||
cloudTasksUtils.enqueue(
|
||||
QUEUE_ASYNC_ACTIONS,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
ResaveEntityAction.PATH, Service.BACKEND.toString(), params, etaDuration));
|
||||
ResaveEntityAction.PATH, Service.BACKEND, params, etaDuration));
|
||||
}
|
||||
}
|
||||
|
||||
+21
-13
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.util;
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
@@ -36,12 +36,18 @@ import com.google.common.net.MediaType;
|
||||
import com.google.common.net.UrlEscapers;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.util.Timestamps;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CollectionUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Utilities for dealing with Cloud Tasks. */
|
||||
@@ -57,11 +63,12 @@ public class CloudTasksUtils implements Serializable {
|
||||
private final String locationId;
|
||||
private final SerializableCloudTasksClient client;
|
||||
|
||||
@Inject
|
||||
public CloudTasksUtils(
|
||||
Retrier retrier,
|
||||
Clock clock,
|
||||
String projectId,
|
||||
String locationId,
|
||||
@Config("projectId") String projectId,
|
||||
@Config("locationId") String locationId,
|
||||
SerializableCloudTasksClient client) {
|
||||
this.retrier = retrier;
|
||||
this.clock = clock;
|
||||
@@ -108,7 +115,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
* the worker service</a>
|
||||
*/
|
||||
private Task createTask(
|
||||
String path, HttpMethod method, String service, Multimap<String, String> params) {
|
||||
String path, HttpMethod method, Service service, Multimap<String, String> params) {
|
||||
checkArgument(
|
||||
path != null && !path.isEmpty() && path.charAt(0) == '/',
|
||||
"The path must start with a '/'.");
|
||||
@@ -119,7 +126,8 @@ public class CloudTasksUtils implements Serializable {
|
||||
AppEngineHttpRequest.Builder requestBuilder =
|
||||
AppEngineHttpRequest.newBuilder()
|
||||
.setHttpMethod(method)
|
||||
.setAppEngineRouting(AppEngineRouting.newBuilder().setService(service).build());
|
||||
.setAppEngineRouting(
|
||||
AppEngineRouting.newBuilder().setService(service.toString()).build());
|
||||
|
||||
if (!CollectionUtils.isNullOrEmpty(params)) {
|
||||
Escaper escaper = UrlEscapers.urlPathSegmentEscaper();
|
||||
@@ -165,7 +173,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
private Task createTaskWithJitter(
|
||||
String path,
|
||||
HttpMethod method,
|
||||
String service,
|
||||
Service service,
|
||||
Multimap<String, String> params,
|
||||
Optional<Integer> jitterSeconds) {
|
||||
if (!jitterSeconds.isPresent() || jitterSeconds.get() <= 0) {
|
||||
@@ -199,7 +207,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
private Task createTaskWithDelay(
|
||||
String path,
|
||||
HttpMethod method,
|
||||
String service,
|
||||
Service service,
|
||||
Multimap<String, String> params,
|
||||
Duration delay) {
|
||||
if (delay.isEqual(Duration.ZERO)) {
|
||||
@@ -211,11 +219,11 @@ public class CloudTasksUtils implements Serializable {
|
||||
.build();
|
||||
}
|
||||
|
||||
public Task createPostTask(String path, String service, Multimap<String, String> params) {
|
||||
public Task createPostTask(String path, Service service, Multimap<String, String> params) {
|
||||
return createTask(path, HttpMethod.POST, service, params);
|
||||
}
|
||||
|
||||
public Task createGetTask(String path, String service, Multimap<String, String> params) {
|
||||
public Task createGetTask(String path, Service service, Multimap<String, String> params) {
|
||||
return createTask(path, HttpMethod.GET, service, params);
|
||||
}
|
||||
|
||||
@@ -224,7 +232,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
*/
|
||||
public Task createPostTaskWithJitter(
|
||||
String path,
|
||||
String service,
|
||||
Service service,
|
||||
Multimap<String, String> params,
|
||||
Optional<Integer> jitterSeconds) {
|
||||
return createTaskWithJitter(path, HttpMethod.POST, service, params, jitterSeconds);
|
||||
@@ -235,7 +243,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
*/
|
||||
public Task createGetTaskWithJitter(
|
||||
String path,
|
||||
String service,
|
||||
Service service,
|
||||
Multimap<String, String> params,
|
||||
Optional<Integer> jitterSeconds) {
|
||||
return createTaskWithJitter(path, HttpMethod.GET, service, params, jitterSeconds);
|
||||
@@ -243,13 +251,13 @@ public class CloudTasksUtils implements Serializable {
|
||||
|
||||
/** Create a {@link Task} via HTTP.POST that will be delayed for {@code delay}. */
|
||||
public Task createPostTaskWithDelay(
|
||||
String path, String service, Multimap<String, String> params, Duration delay) {
|
||||
String path, Service service, Multimap<String, String> params, Duration delay) {
|
||||
return createTaskWithDelay(path, HttpMethod.POST, service, params, delay);
|
||||
}
|
||||
|
||||
/** Create a {@link Task} via HTTP.GET that will be delayed for {@code delay}. */
|
||||
public Task createGetTaskWithDelay(
|
||||
String path, String service, Multimap<String, String> params, Duration delay) {
|
||||
String path, Service service, Multimap<String, String> params, Duration delay) {
|
||||
return createTaskWithDelay(path, HttpMethod.GET, service, params, delay);
|
||||
}
|
||||
|
||||
+11
-8
@@ -138,9 +138,15 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
|
||||
private final boolean isDryRun;
|
||||
private final boolean advanceCursor;
|
||||
private final Counter recurringsInScopeCounter =
|
||||
Metrics.counter("ExpandBilling", "RecurringsInScope");
|
||||
private final Counter expandedOneTimeCounter =
|
||||
Metrics.counter("ExpandBilling", "ExpandedOneTime");
|
||||
Metrics.counter("ExpandBilling", "Recurrings in scope for expansion");
|
||||
// Note that this counter is only accurate when running in dry run mode. Because SQL persistence
|
||||
// is a side effect and not idempotent, a transaction to save OneTimes could be successful but the
|
||||
// transform that contains it could be still be retried, rolling back the counter increment. The
|
||||
// same transform, when retried, would skip the already expanded OneTime, causing this counter to
|
||||
// be lower than it should be when not in dry run mode.
|
||||
// See: https://beam.apache.org/documentation/programming-guide/#user-code-idempotence
|
||||
private final Counter oneTimesToExpandCounter =
|
||||
Metrics.counter("ExpandBilling", "OneTimes that would be expanded");
|
||||
|
||||
ExpandRecurringBillingEventsPipeline(
|
||||
ExpandRecurringBillingEventsPipelineOptions options, Clock clock) {
|
||||
@@ -195,6 +201,7 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
|
||||
endTime.minusYears(1)),
|
||||
true,
|
||||
(BigInteger id) -> {
|
||||
recurringsInScopeCounter.inc();
|
||||
// Note that because all elements are mapped to the same dummy key, the next
|
||||
// batching transform will effectively be serial. This however does not matter for
|
||||
// our use case because the elements were obtained from a SQL read query, which
|
||||
@@ -271,13 +278,9 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
|
||||
} catch (IllegalArgumentException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
recurringsInScopeCounter.inc();
|
||||
Domain domain = tm().loadByKey(Domain.createVKey(recurring.getDomainRepoId()));
|
||||
Registry tld = Registry.get(domain.getTld());
|
||||
|
||||
|
||||
|
||||
// Find the times for which the OneTime billing event are already created, making this expansion
|
||||
// idempotent. There is no need to match to the domain repo ID as the cancellation matching
|
||||
// billing event itself can only be for a single domain.
|
||||
@@ -301,7 +304,7 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
|
||||
// Create new OneTime and DomainHistory for EventTimes that needs to be expanded.
|
||||
for (DateTime eventTime : eventTimesToExpand) {
|
||||
recurrenceLastExpansionTime = latestOf(recurrenceLastExpansionTime, eventTime);
|
||||
expandedOneTimeCounter.inc();
|
||||
oneTimesToExpandCounter.inc();
|
||||
DateTime billingTime = eventTime.plus(tld.getAutoRenewGracePeriodLength());
|
||||
// Note that the DomainHistory is created as of transaction time, as opposed to event time.
|
||||
// This might be counterintuitive because other DomainHistories are created at the time
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.google.auto.value.AutoValue;
|
||||
import com.google.cloud.storage.BlobId;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.gcs.GcsUtils;
|
||||
import google.registry.keyring.api.PgpHelper;
|
||||
import google.registry.model.common.Cursor;
|
||||
@@ -46,7 +47,6 @@ import google.registry.rde.RdeUtil;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.request.RequestParameters;
|
||||
import google.registry.tldconfig.idn.IdnTableEnum;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.xjc.rdeheader.XjcRdeHeader;
|
||||
import google.registry.xjc.rdeheader.XjcRdeHeaderElement;
|
||||
import google.registry.xml.ValidationMode;
|
||||
@@ -306,7 +306,7 @@ public class RdeIO {
|
||||
RDE_UPLOAD_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
RdeUploadAction.PATH,
|
||||
Service.BACKEND.getServiceId(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
RequestParameters.PARAM_TLD,
|
||||
key.tld(),
|
||||
@@ -318,7 +318,7 @@ public class RdeIO {
|
||||
BRDA_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
BrdaCopyAction.PATH,
|
||||
Service.BACKEND.getServiceId(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
RequestParameters.PARAM_TLD,
|
||||
key.tld(),
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.beam.common.RegistryJpaIO;
|
||||
import google.registry.beam.common.RegistryPipelineOptions;
|
||||
import google.registry.config.CloudTasksUtilsModule;
|
||||
@@ -62,7 +63,6 @@ import google.registry.rde.DepositFragment;
|
||||
import google.registry.rde.PendingDeposit;
|
||||
import google.registry.rde.PendingDeposit.PendingDepositCoder;
|
||||
import google.registry.rde.RdeMarshaller;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.UtilsModule;
|
||||
import google.registry.xml.ValidationMode;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
@@ -19,18 +19,15 @@ import com.google.cloud.tasks.v2.CloudTasksClient;
|
||||
import com.google.cloud.tasks.v2.CloudTasksSettings;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.batch.CloudTasksUtils.GcpCloudTasksClient;
|
||||
import google.registry.batch.CloudTasksUtils.SerializableCloudTasksClient;
|
||||
import google.registry.config.CredentialModule.DefaultCredential;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.CloudTasksUtils.GcpCloudTasksClient;
|
||||
import google.registry.util.CloudTasksUtils.SerializableCloudTasksClient;
|
||||
import google.registry.util.GoogleCredentialsBundle;
|
||||
import google.registry.util.Retrier;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.function.Supplier;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* A {@link Module} that provides {@link CloudTasksUtils}.
|
||||
@@ -41,17 +38,6 @@ import javax.inject.Singleton;
|
||||
@Module
|
||||
public abstract class CloudTasksUtilsModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
public static CloudTasksUtils provideCloudTasksUtils(
|
||||
@Config("projectId") String projectId,
|
||||
@Config("locationId") String locationId,
|
||||
SerializableCloudTasksClient client,
|
||||
Retrier retrier,
|
||||
Clock clock) {
|
||||
return new CloudTasksUtils(retrier, clock, projectId, locationId, client);
|
||||
}
|
||||
|
||||
// Provides a supplier instead of using a Dagger @Provider because the latter is not serializable.
|
||||
@Provides
|
||||
public static Supplier<CloudTasksClient> provideCloudTasksClientSupplier(
|
||||
|
||||
@@ -106,6 +106,12 @@ public final class RegistryConfig {
|
||||
return config.gcpProject.projectId;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("cloudSchedulerServiceAccountEmail")
|
||||
public static String provideCloudSchedulerServiceAccountEmail(RegistryConfigSettings config) {
|
||||
return config.gcpProject.cloudSchedulerServiceAccountEmail;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("projectIdNumber")
|
||||
public static long provideProjectIdNumber(RegistryConfigSettings config) {
|
||||
@@ -924,7 +930,7 @@ public final class RegistryConfig {
|
||||
* <p>Note that this uses {@code @Named} instead of {@code @Config} so that it can be used from
|
||||
* the low-level util package, which cannot have a dependency on the config package.
|
||||
*
|
||||
* @see google.registry.util.CloudTasksUtils
|
||||
* @see google.registry.batch.CloudTasksUtils
|
||||
*/
|
||||
@Provides
|
||||
@Named("transientFailureRetries")
|
||||
|
||||
@@ -54,6 +54,7 @@ public class RegistryConfigSettings {
|
||||
public String backendServiceUrl;
|
||||
public String toolsServiceUrl;
|
||||
public String pubapiServiceUrl;
|
||||
public String cloudSchedulerServiceAccountEmail;
|
||||
}
|
||||
|
||||
/** Configuration options for OAuth settings for authenticating users. */
|
||||
|
||||
@@ -22,6 +22,8 @@ gcpProject:
|
||||
backendServiceUrl: https://localhost
|
||||
toolsServiceUrl: https://localhost
|
||||
pubapiServiceUrl: https://localhost
|
||||
# Service account used by Cloud Scheduler to send authenticated requests.
|
||||
cloudSchedulerServiceAccountEmail: cloud-scheduler-email@email.com
|
||||
|
||||
gSuite:
|
||||
# Publicly accessible domain name of the running G Suite instance.
|
||||
@@ -427,7 +429,7 @@ misc:
|
||||
|
||||
beam:
|
||||
# The default region to run Apache Beam (Cloud Dataflow) jobs in.
|
||||
defaultJobRegion: us-east1
|
||||
defaultJobRegion: us-central1
|
||||
# The GCE machine type to use when a job is CPU-intensive (e. g. RDE). Be sure
|
||||
# to check the VM CPU quota for the job region. In a massively parallel
|
||||
# pipeline this quota can be easily reached and needs to be raised, otherwise
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
@@ -45,7 +46,6 @@ import google.registry.request.ParameterMap;
|
||||
import google.registry.request.RequestParameters;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import javax.inject.Inject;
|
||||
@@ -158,6 +158,6 @@ public final class TldFanoutAction implements Runnable {
|
||||
params.put(RequestParameters.PARAM_TLD, tld);
|
||||
}
|
||||
return cloudTasksUtils.createPostTaskWithJitter(
|
||||
endpoint, Service.BACKEND.toString(), params, jitterSeconds);
|
||||
endpoint, Service.BACKEND, params, jitterSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import dagger.Lazy;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.dns.DnsMetrics.ActionStatus;
|
||||
import google.registry.dns.DnsMetrics.CommitStatus;
|
||||
@@ -54,7 +55,6 @@ import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.DomainNameUtils;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.SendEmailService;
|
||||
@@ -339,7 +339,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
DNS_PUBLISH_PUSH_QUEUE_NAME,
|
||||
cloudTasksUtils.createPostTask(
|
||||
PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put(PARAM_TLD, tld)
|
||||
.put(PARAM_DNS_WRITER, dnsWriter)
|
||||
|
||||
@@ -44,6 +44,7 @@ import com.google.common.collect.Ordering;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.hash.HashFunction;
|
||||
import com.google.common.hash.Hashing;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.dns.DnsConstants.TargetType;
|
||||
import google.registry.model.tld.Registries;
|
||||
@@ -53,7 +54,6 @@ import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
@@ -372,7 +372,7 @@ public final class ReadDnsQueueAction implements Runnable {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithJitter(
|
||||
PublishDnsUpdatesAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put(PARAM_TLD, tld)
|
||||
.put(PARAM_DNS_WRITER, dnsWriter)
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<taskentries>
|
||||
<task>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<name>rdeStaging</name>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<schedule>7 0 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
|
||||
<name>rdeUpload</name>
|
||||
<description>
|
||||
This job is a no-op unless RdeUploadCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>0 */4 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
|
||||
<name>tmchDnl</name>
|
||||
<description>
|
||||
This job downloads the latest DNL from MarksDB and inserts it into the database.
|
||||
(See: TmchDnlAction, ClaimsList)
|
||||
</description>
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
|
||||
<name>tmchSmdrl</name>
|
||||
<description>
|
||||
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
|
||||
(See: TmchSmdrlAction, SignedMarkRevocationList)
|
||||
</description>
|
||||
<schedule>15 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
|
||||
<name>tmchCrl</name>
|
||||
<description>
|
||||
This job downloads the latest CRL from MarksDB and inserts it into the database.
|
||||
(See: TmchCrlAction)
|
||||
</description>
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<name>syncGroupMembers</name>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<name>syncRegistrarsSheet</name>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<name>resaveAllEppResourcesPipeline</name>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<!--Deviation from cron tasks schedule: 1st monday of month 09:00 is replaced
|
||||
with 1st of the month 09:00 -->
|
||||
<schedule>0 9 1 * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
|
||||
<name>expandRecurringBillingEvents</name>
|
||||
<description>
|
||||
This job runs an action that creates synthetic OneTime billing events from Recurring billing
|
||||
events. Events are created for all instances of Recurring billing events that should exist
|
||||
between the RECURRING_BILLING cursor's time and the execution time of the action.
|
||||
</description>
|
||||
<schedule>0 3 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<name>deleteExpiredDomains</name>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>7 3 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<name>deleteProberData</name>
|
||||
<description>
|
||||
This job clears out data from probers and runs once a week.
|
||||
</description>
|
||||
<schedule>0 14 * * 1</schedule>
|
||||
</task>
|
||||
|
||||
<!-- TODO: Add borgmon job to check that these files are created and updated successfully. -->
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
|
||||
<name>exportReservedTerms</name>
|
||||
<description>
|
||||
Reserved terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>30 5 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
|
||||
<name>exportPremiumTerms</name>
|
||||
<description>
|
||||
Premium terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>0 5 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<name>readDnsQueue</name>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>*/1 * * * *</schedule>
|
||||
</task>
|
||||
</taskentries>
|
||||
@@ -1,150 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
|
||||
<cronentries>
|
||||
|
||||
<!--
|
||||
/cron/fanout params:
|
||||
queue=<QUEUE_NAME>
|
||||
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
|
||||
runInEmpty // Run once, with no tld parameter
|
||||
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
|
||||
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
|
||||
exclude=TLD1[,TLD2] // exclude something otherwise included
|
||||
-->
|
||||
|
||||
<cron>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<schedule>every day 00:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
|
||||
<description>
|
||||
This job is a no-op unless RdeUploadCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>every 4 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest DNL from MarksDB and inserts it into the database.
|
||||
(See: TmchDnlAction, ClaimsList)
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
|
||||
(See: TmchSmdrlAction, SignedMarkRevocationList)
|
||||
</description>
|
||||
<schedule>every 12 hours from 00:15 to 12:15</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest CRL from MarksDB and inserts it into the database.
|
||||
(See: TmchCrlAction)
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<schedule>1st monday of month 09:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
|
||||
<description>
|
||||
This job runs an action that creates synthetic OneTime billing events from Recurring billing
|
||||
events. Events are created for all instances of Recurring billing events that should exist
|
||||
between the RECURRING_BILLING cursor's time and the execution time of the action.
|
||||
</description>
|
||||
<schedule>every day 03:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>every day 03:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<description>
|
||||
This job clears out data from probers and runs once a week.
|
||||
</description>
|
||||
<schedule>every monday 14:00</schedule>
|
||||
<timezone>UTC</timezone>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<!-- TODO: Add borgmon job to check that these files are created and updated successfully. -->
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
|
||||
<description>
|
||||
Reserved terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>every day 05:30</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
|
||||
<description>
|
||||
Premium terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>every day 05:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>every 1 minutes synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
</cronentries>
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<taskentries>
|
||||
|
||||
<!--
|
||||
/cron/fanout params:
|
||||
queue=<QUEUE_NAME>
|
||||
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
|
||||
runInEmpty // Run once, with no tld parameter
|
||||
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
|
||||
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
|
||||
exclude=TLD1[,TLD2] // exclude something otherwise included
|
||||
-->
|
||||
|
||||
<task>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<name>rdeStaging</name>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<!--
|
||||
This only needs to run once per day, but we launch additional jobs in case the
|
||||
cursor is lagging behind, so it'll catch up to the current date as quickly as
|
||||
possible. The only job that'll run under normal circumstances is the one that's
|
||||
close to midnight, since if the cursor is up-to-date, the task is a no-op.
|
||||
We want it to be close to midnight because that reduces the chance that the
|
||||
point-in-time code won't have to go to the extra trouble of fetching old
|
||||
versions of objects from the database. However, we don't want it to run too
|
||||
close to midnight, because there's always a chance that a change which was
|
||||
timestamped before midnight hasn't fully been committed to the database. So
|
||||
we add a 4+ minute grace period to ensure the transactions cool down, since
|
||||
our queries are not transactional.
|
||||
-->
|
||||
<schedule>7 */4 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
|
||||
<name>rdeUpload</name>
|
||||
<description>
|
||||
This job is a no-op unless RdeUploadCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>0 */4 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-report&endpoint=/_dr/task/rdeReport&forEachRealTld]]></url>
|
||||
<name>rdeReport</name>
|
||||
<description>
|
||||
This job is a no-op unless RdeReportCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>0 */4 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
|
||||
<name>tmchDnl</name>
|
||||
<description>
|
||||
This job downloads the latest DNL from MarksDB and inserts it into the database.
|
||||
(See: TmchDnlAction, ClaimsList)
|
||||
</description>
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
|
||||
<name>tmchSmdrl</name>
|
||||
<description>
|
||||
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
|
||||
(See: TmchSmdrlAction, SignedMarkRevocationList)
|
||||
</description>
|
||||
<schedule>15 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
|
||||
<name>tmchCrl</name>
|
||||
<description>
|
||||
This job downloads the latest CRL from MarksDB and inserts it into the database.
|
||||
(See: TmchCrlAction)
|
||||
</description>
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<name>syncGroupMembers</name>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<name>syncRegistrarsSheet</name>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<name>deleteProberData</name>
|
||||
<description>
|
||||
This job clears out data from probers and runs once a week.
|
||||
</description>
|
||||
<schedule>0 14 * * 1</schedule>
|
||||
</task>
|
||||
|
||||
<!-- TODO: Add borgmon job to check that these files are created and updated successfully. -->
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
|
||||
<name>exportReservedTerms</name>
|
||||
<description>
|
||||
Reserved terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>30 5 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
|
||||
<name>exportPremiumTerms</name>
|
||||
<description>
|
||||
Exports premium price lists to the Google Drive folders for each TLD once per day.
|
||||
</description>
|
||||
<schedule>0 5 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<name>readDnsQueue</name>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>*/1 * * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<name>deleteExpiredDomains</name>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>7 3 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<!--
|
||||
The next two wipeout jobs are required when crash has production data.
|
||||
-->
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/wipeOutCloudSql]]></url>
|
||||
<name>wipeOutCloudSql</name>
|
||||
<description>
|
||||
This job runs an action that deletes all data in Cloud SQL.
|
||||
</description>
|
||||
<schedule>7 3 * * 6</schedule>
|
||||
</task>
|
||||
</taskentries>
|
||||
@@ -1,165 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
|
||||
<cronentries>
|
||||
|
||||
<!--
|
||||
/cron/fanout params:
|
||||
queue=<QUEUE_NAME>
|
||||
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
|
||||
runInEmpty // Run once, with no tld parameter
|
||||
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
|
||||
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
|
||||
exclude=TLD1[,TLD2] // exclude something otherwise included
|
||||
-->
|
||||
|
||||
<cron>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<!--
|
||||
This only needs to run once per day, but we launch additional jobs in case the
|
||||
cursor is lagging behind, so it'll catch up to the current date as quickly as
|
||||
possible. The only job that'll run under normal circumstances is the one that's
|
||||
close to midnight, since if the cursor is up-to-date, the task is a no-op.
|
||||
|
||||
We want it to be close to midnight because that reduces the chance that the
|
||||
point-in-time code won't have to go to the extra trouble of fetching old
|
||||
versions of objects from the database. However, we don't want it to run too
|
||||
close to midnight, because there's always a chance that a change which was
|
||||
timestamped before midnight hasn't fully been committed to the database. So
|
||||
we add a 4+ minute grace period to ensure the transactions cool down, since
|
||||
our queries are not transactional.
|
||||
-->
|
||||
<schedule>every 4 hours from 00:07 to 20:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
|
||||
<description>
|
||||
This job is a no-op unless RdeUploadCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>every 4 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-report&endpoint=/_dr/task/rdeReport&forEachRealTld]]></url>
|
||||
<description>
|
||||
This job is a no-op unless RdeReportCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>every 4 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest DNL from MarksDB and inserts it into the database.
|
||||
(See: TmchDnlAction, ClaimsList)
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
|
||||
(See: TmchSmdrlAction, SignedMarkRevocationList)
|
||||
</description>
|
||||
<schedule>every 12 hours from 00:15 to 12:15</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest CRL from MarksDB and inserts it into the database.
|
||||
(See: TmchCrlAction)
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<description>
|
||||
This job clears out data from probers and runs once a week.
|
||||
</description>
|
||||
<schedule>every monday 14:00</schedule>
|
||||
<timezone>UTC</timezone>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<!-- TODO: Add borgmon job to check that these files are created and updated successfully. -->
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
|
||||
<description>
|
||||
Reserved terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>every day 05:30</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
|
||||
<description>
|
||||
Exports premium price lists to the Google Drive folders for each TLD once per day.
|
||||
</description>
|
||||
<schedule>every day 05:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>every 1 minutes synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>every day 03:07</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>
|
||||
</cronentries>
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<manual-scaling>
|
||||
<instances>12</instances>
|
||||
<instances>24</instances>
|
||||
</manual-scaling>
|
||||
|
||||
<system-properties>
|
||||
|
||||
Vendored
+299
@@ -0,0 +1,299 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<taskentries>
|
||||
<task>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<name>rdeStaging</name>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<!--
|
||||
This only needs to run once per day, but we launch additional jobs in case the
|
||||
cursor is lagging behind, so it'll catch up to the current date as quickly as
|
||||
possible. The only job that'll run under normal circumstances is the one that's
|
||||
close to midnight, since if the cursor is up-to-date, the task is a no-op.
|
||||
We want it to be close to midnight because that reduces the chance that the
|
||||
point-in-time code won't have to go to the extra trouble of fetching old
|
||||
versions of objects from the database. However, we don't want it to run too
|
||||
close to midnight, because there's always a chance that a change which was
|
||||
timestamped before midnight hasn't fully been committed to the database. So
|
||||
we add a 4+ minute grace period to ensure the transactions cool down, since
|
||||
our queries are not transactional.
|
||||
-->
|
||||
<schedule>7 */8 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
|
||||
<name>rdeUpload</name>
|
||||
<description>
|
||||
This job is a no-op unless RdeUploadCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>0 */4 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-report&endpoint=/_dr/task/rdeReport&forEachRealTld]]></url>
|
||||
<name>rdeReport</name>
|
||||
<description>
|
||||
This job is a no-op unless RdeReportCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>0 */4 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
|
||||
<name>tmchDnl</name>
|
||||
<description>
|
||||
This job downloads the latest DNL from MarksDB and inserts it into the database.
|
||||
(See: TmchDnlAction, ClaimsList)
|
||||
</description>
|
||||
<schedule>0 0,12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
|
||||
<name>tmchSmdrl</name>
|
||||
<description>
|
||||
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
|
||||
(See: TmchSmdrlAction, SignedMarkRevocationList)
|
||||
</description>
|
||||
<schedule>15 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
|
||||
<name>tmchCrl</name>
|
||||
<description>
|
||||
This job downloads the latest CRL from MarksDB and inserts it into the database.
|
||||
(See: TmchCrlAction)
|
||||
</description>
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<name>syncGroupMembers</name>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<name>syncRegistrarsSheet</name>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<name>resaveAllEppResourcesPipeline</name>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<!--
|
||||
Deviation from cron tasks schedule: 1st monday of month 09:00 is replaced
|
||||
with 1st of the month 09:00
|
||||
-->
|
||||
<schedule>0 9 1 * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/updateRegistrarRdapBaseUrls]]></url>
|
||||
<name>updateRegistrarRdapBaseUrls</name>
|
||||
<description>
|
||||
This job reloads all registrar RDAP base URLs from ICANN.
|
||||
</description>
|
||||
<schedule>34 2 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
|
||||
<name>exportDomainLists</name>
|
||||
<description>
|
||||
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
|
||||
</description>
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
|
||||
<name>expandRecurringBillingEvents</name>
|
||||
<description>
|
||||
This job runs an action that creates synthetic OneTime billing events from Recurring billing
|
||||
events. Events are created for all instances of Recurring billing events that should exist
|
||||
between the RECURRING_BILLING cursor's time and the execution time of the action.
|
||||
</description>
|
||||
<schedule>0 3 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<name>deleteExpiredDomains</name>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>7 3 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/sendExpiringCertificateNotificationEmail]]></url>
|
||||
<name>sendExpiringCertificateNotificationEmail</name>
|
||||
<description>
|
||||
This job runs an action that sends emails to partners if their certificates are expiring soon.
|
||||
</description>
|
||||
<schedule>30 4 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=sunrise]]></url>
|
||||
<name>nordnUploadSunrise</name>
|
||||
<description>
|
||||
This job uploads LORDN Sunrise CSV files for each TLD to MarksDB. It should be
|
||||
run at most every three hours, or at absolute minimum every 26 hours.
|
||||
</description>
|
||||
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=claims]]></url>
|
||||
<name>nordnUploadClaims</name>
|
||||
<description>
|
||||
This job uploads LORDN Claims CSV files for each TLD to MarksDB. It should be
|
||||
run at most every three hours, or at absolute minimum every 26 hours.
|
||||
</description>
|
||||
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=sunrise&pullQueue]]></url>
|
||||
<name>nordnUploadSunrisePullQueue</name>
|
||||
<description>
|
||||
This job uploads LORDN Sunrise CSV files for each TLD to MarksDB using
|
||||
pull queue. It should be run at most every three hours, or at absolute
|
||||
minimum every 26 hours.
|
||||
</description>
|
||||
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=claims&pullQueue]]></url>
|
||||
<name>nordnUploadClaimsPullQueue</name>
|
||||
<description>
|
||||
This job uploads LORDN Claims CSV files for each TLD to MarksDB using pull
|
||||
queue. It should be run at most every three hours, or at absolute minimum
|
||||
every 26 hours.
|
||||
</description>
|
||||
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<name>deleteProberData</name>
|
||||
<description>
|
||||
This job clears out data from probers and runs once a week.
|
||||
</description>
|
||||
<schedule>0 14 * * 1</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
|
||||
<name>exportReservedTerms</name>
|
||||
<description>
|
||||
Reserved terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>30 5 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
|
||||
<name>exportPremiumTerms</name>
|
||||
<description>
|
||||
Exports premium price lists to the Google Drive folders for each TLD once per day.
|
||||
</description>
|
||||
<schedule>0 5 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<name>readDnsQueue</name>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>*/1 * * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/icannReportingStaging&runInEmpty]]></url>
|
||||
<name>icannReportingStaging</name>
|
||||
<description>
|
||||
Create ICANN activity and transaction reports for last month, storing them in
|
||||
gs://[PROJECT-ID]-reporting/icann/monthly/yyyy-MM
|
||||
Upon success, enqueues the icannReportingUpload task to POST these files to ICANN.
|
||||
</description>
|
||||
<schedule>0 9 2 * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/icannReportingUpload&runInEmpty]]></url>
|
||||
<name>icannReportingUpload</name>
|
||||
<description>
|
||||
Checks if the monthly ICANN reports have been successfully uploaded. If they have not, attempts to upload them again.
|
||||
Most of the time, this job should not do anything since the uploads are triggered when the reports are staged.
|
||||
However, in the event that an upload failed for any reason (e.g. ICANN server is down, IP allow list issues),
|
||||
this cron job will continue to retry uploads daily until they succeed.
|
||||
</description>
|
||||
<schedule>0 15 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/generateInvoices?shouldPublish=true&runInEmpty]]></url>
|
||||
<name>generateInvoices</name>
|
||||
<description>
|
||||
Starts the beam/billing/InvoicingPipeline Dataflow template, which creates the overall invoice and
|
||||
detail report CSVs for last month, storing them in gs://[PROJECT-ID]-billing/invoices/yyyy-MM.
|
||||
Upon success, sends an e-mail copy of the invoice to billing personnel, and copies detail
|
||||
reports to the associated registrars' drive folders.
|
||||
See GenerateInvoicesAction for more details.
|
||||
</description>
|
||||
<!--WARNING: This must occur AFTER expandRecurringBillingEvents and AFTER exportSnapshot, as
|
||||
it uses Bigquery as the source of truth for billable events. ExportSnapshot usually takes
|
||||
about 2 hours to complete, so we give 11 hours to be safe. Normally, we give 24+ hours (see
|
||||
icannReportingStaging), but the invoicing team prefers receiving the e-mail on the first of
|
||||
each month. -->
|
||||
<schedule>0 19 1 * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/generateSpec11&runInEmpty]]></url>
|
||||
<name>generateSpec11</name>
|
||||
<description>
|
||||
Starts the beam/spec11/Spec11Pipeline Dataflow template, which creates today's Spec11
|
||||
report. This report is stored in gs://[PROJECT-ID]-reporting/icann/spec11/yyyy-MM/.
|
||||
This job will only send email notifications on the second of every month.
|
||||
See GenerateSpec11ReportAction for more details.
|
||||
</description>
|
||||
<schedule>0 15 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
|
||||
<name>wipeOutContactHistoryPii</name>
|
||||
<description>
|
||||
This job runs weekly to wipe out PII fields of ContactHistory entities
|
||||
that have been in the database for a certain period of time.
|
||||
</description>
|
||||
<schedule>0 15 * * 1</schedule>
|
||||
</task>
|
||||
</taskentries>
|
||||
+1
-285
@@ -1,288 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
|
||||
<cronentries>
|
||||
|
||||
<!--
|
||||
/cron/fanout params:
|
||||
queue=<QUEUE_NAME>
|
||||
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
|
||||
runInEmpty // Run once, with no tld parameter
|
||||
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
|
||||
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
|
||||
exclude=TLD1[,TLD2] // exclude something otherwise included
|
||||
-->
|
||||
|
||||
<cron>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<!--
|
||||
This only needs to run once per day, but we launch additional jobs in case the
|
||||
cursor is lagging behind, so it'll catch up to the current date as quickly as
|
||||
possible. The only job that'll run under normal circumstances is the one that's
|
||||
close to midnight, since if the cursor is up-to-date, the task is a no-op.
|
||||
|
||||
We want it to be close to midnight because that reduces the chance that the
|
||||
point-in-time code won't have to go to the extra trouble of fetching old
|
||||
versions of objects from the database. However, we don't want it to run too
|
||||
close to midnight, because there's always a chance that a change which was
|
||||
timestamped before midnight hasn't fully been committed to the database. So
|
||||
we add a 4+ minute grace period to ensure the transactions cool down, since
|
||||
our queries are not transactional.
|
||||
-->
|
||||
<schedule>every 8 hours from 00:07 to 20:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
|
||||
<description>
|
||||
This job is a no-op unless RdeUploadCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>every 4 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-report&endpoint=/_dr/task/rdeReport&forEachRealTld]]></url>
|
||||
<description>
|
||||
This job is a no-op unless RdeReportCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>every 4 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest DNL from MarksDB and inserts it into the database.
|
||||
(See: TmchDnlAction, ClaimsList)
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
|
||||
(See: TmchSmdrlAction, SignedMarkRevocationList)
|
||||
</description>
|
||||
<schedule>every 12 hours from 00:15 to 12:15</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest CRL from MarksDB and inserts it into the database.
|
||||
(See: TmchCrlAction)
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<!-- TODO(b/249863289): disable until it is safe to run this pipeline
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<schedule>1st monday of month 09:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
-->
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/updateRegistrarRdapBaseUrls]]></url>
|
||||
<description>
|
||||
This job reloads all registrar RDAP base URLs from ICANN.
|
||||
</description>
|
||||
<schedule>every day 02:34</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
|
||||
<description>
|
||||
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
|
||||
<description>
|
||||
This job runs an action that creates synthetic OneTime billing events from Recurring billing
|
||||
events. Events are created for all instances of Recurring billing events that should exist
|
||||
between the RECURRING_BILLING cursor's time and the execution time of the action.
|
||||
</description>
|
||||
<schedule>every day 03:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>every day 03:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/sendExpiringCertificateNotificationEmail]]></url>
|
||||
<description>
|
||||
This job runs an action that sends emails to partners if their certificates are expiring soon.
|
||||
</description>
|
||||
<schedule>every day 04:30</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordn-phase=sunrise]]></url>
|
||||
<description>
|
||||
This job uploads LORDN Sunrise CSV files for each TLD to MarksDB. It should be
|
||||
run at most every three hours, or at absolute minimum every 26 hours.
|
||||
</description>
|
||||
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<timezone>UTC</timezone>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordn-phase=claims]]></url>
|
||||
<description>
|
||||
This job uploads LORDN Claims CSV files for each TLD to MarksDB. It should be
|
||||
run at most every three hours, or at absolute minimum every 26 hours.
|
||||
</description>
|
||||
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<timezone>UTC</timezone>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<description>
|
||||
This job clears out data from probers and runs once a week.
|
||||
</description>
|
||||
<schedule>every monday 14:00</schedule>
|
||||
<timezone>UTC</timezone>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
|
||||
<description>
|
||||
Reserved terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>every day 05:30</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
|
||||
<description>
|
||||
Exports premium price lists to the Google Drive folders for each TLD once per day.
|
||||
</description>
|
||||
<schedule>every day 05:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>every 1 minutes synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/icannReportingStaging&runInEmpty]]></url>
|
||||
<description>
|
||||
Create ICANN activity and transaction reports for last month, storing them in
|
||||
gs://[PROJECT-ID]-reporting/icann/monthly/yyyy-MM
|
||||
Upon success, enqueues the icannReportingUpload task to POST these files to ICANN.
|
||||
</description>
|
||||
<schedule>2 of month 09:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/icannReportingUpload&runInEmpty]]></url>
|
||||
<description>
|
||||
Checks if the monthly ICANN reports have been successfully uploaded. If they have not, attempts to upload them again.
|
||||
Most of the time, this job should not do anything since the uploads are triggered when the reports are staged.
|
||||
However, in the event that an upload failed for any reason (e.g. ICANN server is down, IP allow list issues),
|
||||
this cron job will continue to retry uploads daily until they succeed.
|
||||
</description>
|
||||
<schedule>every day 15:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/generateInvoices?shouldPublish=true&runInEmpty]]></url>
|
||||
<description>
|
||||
Starts the beam/billing/InvoicingPipeline Dataflow template, which creates the overall invoice and
|
||||
detail report CSVs for last month, storing them in gs://[PROJECT-ID]-billing/invoices/yyyy-MM.
|
||||
Upon success, sends an e-mail copy of the invoice to billing personnel, and copies detail
|
||||
reports to the associated registrars' drive folders.
|
||||
See GenerateInvoicesAction for more details.
|
||||
</description>
|
||||
<!--WARNING: This must occur AFTER expandRecurringBillingEvents and AFTER exportSnapshot, as
|
||||
it uses Bigquery as the source of truth for billable events. ExportSnapshot usually takes
|
||||
about 2 hours to complete, so we give 11 hours to be safe. Normally, we give 24+ hours (see
|
||||
icannReportingStaging), but the invoicing team prefers receiving the e-mail on the first of
|
||||
each month. -->
|
||||
<schedule>1 of month 19:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/generateSpec11&runInEmpty]]></url>
|
||||
<description>
|
||||
Starts the beam/spec11/Spec11Pipeline Dataflow template, which creates today's Spec11
|
||||
report. This report is stored in gs://[PROJECT-ID]-reporting/icann/spec11/yyyy-MM/.
|
||||
This job will only send email notifications on the second of every month.
|
||||
See GenerateSpec11ReportAction for more details.
|
||||
</description>
|
||||
<schedule>every day 15:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
|
||||
<description>
|
||||
This job runs weekly to wipe out PII fields of ContactHistory entities
|
||||
that have been in the database for a certain period of time.
|
||||
</description>
|
||||
<schedule>every monday 15:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
</cronentries>
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<taskentries>
|
||||
<task>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<name>rdeStaging</name>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<schedule>7 0 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<name>readDnsQueue</name>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>*/1 * * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<name>syncRegistrarsSheet</name>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<name>resaveAllEppResourcesPipeline</name>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<!--Deviation from cron tasks schedule: 1st monday of month 09:00 is replaced
|
||||
with 1st of the month 09:00 -->
|
||||
<schedule>0 9 1 * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<name>syncGroupMembers</name>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<name>deleteExpiredDomains</name>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>7 3 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/wipeOutCloudSql]]></url>
|
||||
<name>wipeOutCloudSql</name>
|
||||
<description>
|
||||
This job runs an action that deletes all data in Cloud SQL.
|
||||
</description>
|
||||
<schedule>7 3 * * 6</schedule>
|
||||
</task>
|
||||
</taskentries>
|
||||
@@ -1,70 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
|
||||
<cronentries>
|
||||
|
||||
<cron>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<schedule>every day 00:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>every 1 minutes synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<schedule>1st monday of month 09:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>every day 03:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<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>
|
||||
</cronentries>
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<taskentries>
|
||||
<task>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<name>rdeStaging</name>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<!--
|
||||
This only needs to run once per day, but we launch additional jobs in case the
|
||||
cursor is lagging behind, so it'll catch up to the current date eventually.
|
||||
|
||||
See <a href="../../../production/default/WEB-INF/cron.xml">production config</a> for an
|
||||
explanation of job starting times.
|
||||
-->
|
||||
<schedule>7 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
|
||||
<name>rdeUpload</name>
|
||||
<description>
|
||||
This job is a no-op unless RdeUploadCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>0 */4 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
|
||||
<name>tmchDnl</name>
|
||||
<description>
|
||||
This job downloads the latest DNL from MarksDB and inserts it into the database.
|
||||
(See: TmchDnlAction, ClaimsList)
|
||||
</description>
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
|
||||
<name>tmchSmdrl</name>
|
||||
<description>
|
||||
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
|
||||
(See: TmchSmdrlAction, SignedMarkRevocationList)
|
||||
</description>
|
||||
<schedule>15 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
|
||||
<name>tmchCrl</name>
|
||||
<description>
|
||||
This job downloads the latest CRL from MarksDB and inserts it into the database.
|
||||
(See: TmchCrlAction)
|
||||
</description>
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<name>syncGroupMembers</name>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<name>syncRegistrarsSheet</name>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
|
||||
<name>exportDomainLists</name>
|
||||
<description>
|
||||
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
|
||||
</description>
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
|
||||
<name>expandRecurringBillingEvents</name>
|
||||
<description>
|
||||
This job runs an action that creates synthetic OneTime billing events from Recurring billing
|
||||
events. Events are created for all instances of Recurring billing events that should exist
|
||||
between the RECURRING_BILLING cursor's time and the execution time of the action.
|
||||
</description>
|
||||
<schedule>0 3 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<name>resaveAllEppResourcesPipeline</name>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<!--
|
||||
Deviation from cron tasks schedule: 1st monday of month 09:00 is replaced
|
||||
with 1st of the month 09:00
|
||||
-->
|
||||
<schedule>0 9 1 * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<name>deleteExpiredDomains</name>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>7 3 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<name>deleteProberData</name>
|
||||
<description>
|
||||
This job clears out data from probers and runs once a week.
|
||||
</description>
|
||||
<schedule>0 14 * * 1</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
|
||||
<name>exportReservedTerms</name>
|
||||
<description>
|
||||
Reserved terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>30 5 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
|
||||
<name>exportPremiumTerms</name>
|
||||
<description>
|
||||
Exports premium price lists to the Google Drive folders for each TLD once per day.
|
||||
</description>
|
||||
<schedule>0 5 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<name>readDnsQueue</name>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>*/1 * * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
|
||||
<name>wipeOutContactHistoryPii</name>
|
||||
<description>
|
||||
This job runs weekly to wipe out PII fields of ContactHistory entities
|
||||
that have been in the database for a certain period of time.
|
||||
</description>
|
||||
<schedule>0 15 * * 1</schedule>
|
||||
</task>
|
||||
</taskentries>
|
||||
@@ -1,177 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
|
||||
<cronentries>
|
||||
|
||||
<!--
|
||||
/cron/fanout params:
|
||||
queue=<QUEUE_NAME>
|
||||
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
|
||||
runInEmpty // Run once, with no tld parameter
|
||||
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
|
||||
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
|
||||
exclude=TLD1[,TLD2] // exclude something otherwise included
|
||||
-->
|
||||
|
||||
<cron>
|
||||
<url>/_dr/task/rdeStaging</url>
|
||||
<description>
|
||||
This job generates a full RDE escrow deposit as a single gigantic XML document
|
||||
and streams it to cloud storage. When this job has finished successfully, it'll
|
||||
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
|
||||
</description>
|
||||
<!--
|
||||
This only needs to run once per day, but we launch additional jobs in case the
|
||||
cursor is lagging behind, so it'll catch up to the current date eventually.
|
||||
|
||||
See <a href="../../../production/default/WEB-INF/cron.xml">production config</a> for an
|
||||
explanation of job starting times.
|
||||
-->
|
||||
<schedule>every 12 hours from 00:07 to 12:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
|
||||
<description>
|
||||
This job is a no-op unless RdeUploadCursor falls behind for some reason.
|
||||
</description>
|
||||
<schedule>every 4 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest DNL from MarksDB and inserts it into the database.
|
||||
(See: TmchDnlAction, ClaimsList)
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
|
||||
(See: TmchSmdrlAction, SignedMarkRevocationList)
|
||||
</description>
|
||||
<schedule>every 12 hours from 00:15 to 12:15</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
|
||||
<description>
|
||||
This job downloads the latest CRL from MarksDB and inserts it into the database.
|
||||
(See: TmchCrlAction)
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
|
||||
<description>
|
||||
Syncs RegistrarContact changes in the past hour to Google Groups.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
|
||||
<description>
|
||||
Synchronize Registrar entities to Google Spreadsheets.
|
||||
</description>
|
||||
<schedule>every 1 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<!-- TODO(b/249863289): disable until it is safe to run this pipeline
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<schedule>1st monday of month 09:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
-->
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
|
||||
<description>
|
||||
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
|
||||
<description>
|
||||
This job runs an action that creates synthetic OneTime billing events from Recurring billing
|
||||
events. Events are created for all instances of Recurring billing events that should exist
|
||||
between the RECURRING_BILLING cursor's time and the execution time of the action.
|
||||
</description>
|
||||
<schedule>every day 03:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<description>
|
||||
This job runs an action that deletes domains that are past their
|
||||
autorenew end date.
|
||||
</description>
|
||||
<schedule>every day 03:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<description>
|
||||
This job clears out data from probers and runs once a week.
|
||||
</description>
|
||||
<schedule>every monday 14:00</schedule>
|
||||
<timezone>UTC</timezone>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
|
||||
<description>
|
||||
Reserved terms export to Google Drive job for creating once-daily exports.
|
||||
</description>
|
||||
<schedule>every day 05:30</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
|
||||
<description>
|
||||
Exports premium price lists to the Google Drive folders for each TLD once per day.
|
||||
</description>
|
||||
<schedule>every day 05:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<description>
|
||||
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
|
||||
group.
|
||||
</description>
|
||||
<schedule>every 1 minutes synchronized</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
|
||||
<description>
|
||||
This job runs weekly to wipe out PII fields of ContactHistory entities
|
||||
that have been in the database for a certain period of time.
|
||||
</description>
|
||||
<schedule>every monday 15:00</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
</cronentries>
|
||||
|
||||
@@ -86,6 +86,8 @@ import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.billing.BillingEvent.Recurring;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.domain.DomainCommand.Create;
|
||||
@@ -123,6 +125,7 @@ import google.registry.model.tmch.ClaimsList;
|
||||
import google.registry.model.tmch.ClaimsListDao;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.tmch.LordnTaskUtils;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -277,8 +280,12 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
registrarId,
|
||||
now,
|
||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
boolean defaultTokenUsed = false;
|
||||
if (!allocationToken.isPresent() && !registry.getDefaultPromoTokens().isEmpty()) {
|
||||
allocationToken = checkForDefaultToken(registry, command);
|
||||
if (allocationToken.isPresent()) {
|
||||
defaultTokenUsed = true;
|
||||
}
|
||||
}
|
||||
boolean isAnchorTenant =
|
||||
isAnchorTenant(
|
||||
@@ -337,7 +344,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
FeesAndCredits feesAndCredits =
|
||||
pricingLogic.getCreatePrice(
|
||||
registry, targetId, now, years, isAnchorTenant, allocationToken);
|
||||
validateFeeChallenge(feeCreate, feesAndCredits);
|
||||
validateFeeChallenge(feeCreate, feesAndCredits, defaultTokenUsed);
|
||||
Optional<SecDnsCreateExtension> secDnsCreate =
|
||||
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
|
||||
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
|
||||
@@ -377,7 +384,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
reservationTypes.contains(NAME_COLLISION)
|
||||
? ImmutableSet.of(SERVER_HOLD)
|
||||
: ImmutableSet.of();
|
||||
Domain domain =
|
||||
Domain.Builder domainBuilder =
|
||||
new Domain.Builder()
|
||||
.setCreationRegistrarId(registrarId)
|
||||
.setPersistedCurrentSponsorRegistrarId(registrarId)
|
||||
@@ -397,7 +404,14 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
.setContacts(command.getContacts())
|
||||
.addGracePeriod(
|
||||
GracePeriod.forBillingEvent(GracePeriodStatus.ADD, repoId, createBillingEvent))
|
||||
.build();
|
||||
.setLordnPhase(
|
||||
!DatabaseMigrationStateSchedule.getValueAtTime(tm().getTransactionTime())
|
||||
.equals(MigrationState.NORDN_SQL)
|
||||
? LordnPhase.NONE
|
||||
: hasSignedMarks
|
||||
? LordnPhase.SUNRISE
|
||||
: hasClaimsNotice ? LordnPhase.CLAIMS : LordnPhase.NONE);
|
||||
Domain domain = domainBuilder.build();
|
||||
if (allocationToken.isPresent()
|
||||
&& allocationToken.get().getTokenType().equals(TokenType.PACKAGE)) {
|
||||
if (years > 1) {
|
||||
@@ -697,7 +711,9 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
if (newDomain.shouldPublishToDns()) {
|
||||
dnsQueue.addDomainRefreshTask(newDomain.getDomainName());
|
||||
}
|
||||
if (hasClaimsNotice || hasSignedMarks) {
|
||||
if (!DatabaseMigrationStateSchedule.getValueAtTime(tm().getTransactionTime())
|
||||
.equals(MigrationState.NORDN_SQL)
|
||||
&& (hasClaimsNotice || hasSignedMarks)) {
|
||||
LordnTaskUtils.enqueueDomainTask(newDomain);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,12 +778,13 @@ public class DomainFlowUtils {
|
||||
*/
|
||||
public static void validateFeeChallenge(
|
||||
final Optional<? extends FeeTransformCommandExtension> feeCommand,
|
||||
FeesAndCredits feesAndCredits)
|
||||
FeesAndCredits feesAndCredits,
|
||||
boolean defaultTokenUsed)
|
||||
throws EppException {
|
||||
if (feesAndCredits.hasAnyPremiumFees() && !feeCommand.isPresent()) {
|
||||
throw new FeesRequiredForPremiumNameException();
|
||||
}
|
||||
validateFeesAckedIfPresent(feeCommand, feesAndCredits);
|
||||
validateFeesAckedIfPresent(feeCommand, feesAndCredits, defaultTokenUsed);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -795,7 +796,8 @@ public class DomainFlowUtils {
|
||||
*/
|
||||
public static void validateFeesAckedIfPresent(
|
||||
final Optional<? extends FeeTransformCommandExtension> feeCommand,
|
||||
FeesAndCredits feesAndCredits)
|
||||
FeesAndCredits feesAndCredits,
|
||||
boolean defaultTokenUsed)
|
||||
throws EppException {
|
||||
// Check for the case where a fee command extension was required but not provided.
|
||||
// This only happens when the total fees are non-zero and include custom fees requiring the
|
||||
@@ -856,7 +858,9 @@ public class DomainFlowUtils {
|
||||
// Checking if total amount is expected. Extra fees that we are not expecting may be passed in.
|
||||
// Or if there is only a single fee type expected.
|
||||
if (!feeTotal.equals(feesAndCredits.getTotalCost())) {
|
||||
throw new FeesMismatchException(feesAndCredits.getTotalCost());
|
||||
if (!defaultTokenUsed || feeTotal.isLessThan(feesAndCredits.getTotalCost())) {
|
||||
throw new FeesMismatchException(feesAndCredits.getTotalCost());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
|
||||
now,
|
||||
years,
|
||||
existingRecurringBillingEvent);
|
||||
validateFeeChallenge(feeRenew, feesAndCredits);
|
||||
validateFeeChallenge(feeRenew, feesAndCredits, false);
|
||||
flowCustomLogic.afterValidation(
|
||||
AfterValidationParameters.newBuilder()
|
||||
.setExistingDomain(existingDomain)
|
||||
|
||||
@@ -226,7 +226,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
|
||||
if (!existingDomain.getGracePeriodStatuses().contains(GracePeriodStatus.REDEMPTION)) {
|
||||
throw new DomainNotEligibleForRestoreException();
|
||||
}
|
||||
validateFeeChallenge(feeUpdate, feesAndCredits);
|
||||
validateFeeChallenge(feeUpdate, feesAndCredits, false);
|
||||
}
|
||||
|
||||
private static Domain performRestore(
|
||||
|
||||
@@ -210,7 +210,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
|
||||
}
|
||||
|
||||
if (feesAndCredits.isPresent()) {
|
||||
validateFeeChallenge(feeTransfer, feesAndCredits.get());
|
||||
validateFeeChallenge(feeTransfer, feesAndCredits.get(), false);
|
||||
}
|
||||
HistoryEntryId domainHistoryId = createHistoryEntryId(existingDomain);
|
||||
historyBuilder
|
||||
|
||||
@@ -231,7 +231,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
|
||||
Optional<FeeUpdateCommandExtension> feeUpdate =
|
||||
eppInput.getSingleExtension(FeeUpdateCommandExtension.class);
|
||||
FeesAndCredits feesAndCredits = pricingLogic.getUpdatePrice(registry, targetId, now);
|
||||
validateFeesAckedIfPresent(feeUpdate, feesAndCredits);
|
||||
validateFeesAckedIfPresent(feeUpdate, feesAndCredits, false);
|
||||
verifyNotInPendingDelete(
|
||||
add.getContacts(),
|
||||
command.getInnerChange().getRegistrant(),
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.google.cloud.tasks.v2.Task;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.RefreshDnsOnHostRenameAction;
|
||||
import google.registry.flows.EppException;
|
||||
@@ -65,7 +66,6 @@ import google.registry.model.host.HostHistory;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
@@ -280,7 +280,7 @@ public final class HostUpdateFlow implements TransactionalFlow {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTask(
|
||||
RefreshDnsOnHostRenameAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(PARAM_HOST_KEY, existingHost.createVKey().stringify()));
|
||||
cloudTasksUtils.enqueue(QUEUE_HOST_RENAME, task);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@ U+011F # LATIN SMALL LETTER G WITH BREVE
|
||||
U+01E7 # LATIN SMALL LETTER G WITH CARON
|
||||
U+0121 # LATIN SMALL LETTER G WITH DOT ABOVE
|
||||
U+0123 # LATIN SMALL LETTER G WITH CEDILLA
|
||||
U+01E5 # LATIN SMALL LETTER G WITH STROKE
|
||||
U+0068 # LATIN SMALL LETTER H
|
||||
U+0127 # LATIN SMALL LETTER H WITH STROKE
|
||||
U+0069 # LATIN SMALL LETTER I
|
||||
|
||||
@@ -28,13 +28,13 @@ import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.protobuf.Timestamp;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
@@ -337,7 +337,7 @@ public class LoadTestAction implements Runnable {
|
||||
cloudTasksUtils
|
||||
.createPostTask(
|
||||
"/_dr/epptool",
|
||||
Service.TOOLS.toString(),
|
||||
Service.TOOLS,
|
||||
ImmutableMultimap.of(
|
||||
"clientId",
|
||||
registrarId,
|
||||
|
||||
@@ -33,7 +33,6 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.config.RegistryConfig;
|
||||
import google.registry.dns.RefreshDnsAction;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.persistence.VKey;
|
||||
@@ -42,7 +41,6 @@ import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.AttributeOverride;
|
||||
@@ -137,23 +135,6 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||
/** Status values associated with this resource. */
|
||||
@Expose Set<StatusValue> statuses;
|
||||
|
||||
/**
|
||||
* When this domain/host's DNS was requested to be refreshed, or null if its DNS is up-to-date.
|
||||
*
|
||||
* <p>This will almost always be null except in the couple of minutes' interval between when a
|
||||
* DNS-affecting create or update operation takes place and when the {@link RefreshDnsAction}
|
||||
* runs, which resets this back to null upon completion of the DNS refresh task. This is a {@link
|
||||
* DateTime} rather than a simple dirty boolean so that the DNS refresh action can order by the
|
||||
* DNS refresh request time and take action on the oldest ones first.
|
||||
*
|
||||
* <p>Note that in the {@code DomainHistory}/{@code HostHistory} table this value means something
|
||||
* slightly different: It means that the given domain/host action requested a DNS update. Unlike
|
||||
* on the {@code Domain}/{code Host} table, this value is not then subsequently nulled out once
|
||||
* the DNS refresh is complete; rather, it remains as a permanent record of which actions were
|
||||
* DNS-affecting and which were not.
|
||||
*/
|
||||
@Transient @Nullable protected DateTime dnsRefreshRequestTime;
|
||||
|
||||
public String getRepoId() {
|
||||
return repoId;
|
||||
}
|
||||
@@ -205,19 +186,6 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||
return deletionTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DNS refresh request time iff this domain/host's DNS needs refreshing, otherwise
|
||||
* absent.
|
||||
*/
|
||||
public Optional<DateTime> getDnsRefreshRequestTime() {
|
||||
return Optional.ofNullable(dnsRefreshRequestTime);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void setInternalDnsRefreshRequestTime(DateTime time) {
|
||||
dnsRefreshRequestTime = time;
|
||||
}
|
||||
|
||||
/** Return a clone of the resource with timed status values modified using the given time. */
|
||||
public abstract EppResource cloneProjectedAtTime(DateTime now);
|
||||
|
||||
@@ -371,11 +339,6 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B setDnsRefreshRequestTime(Optional<DateTime> dnsRefreshRequestTime) {
|
||||
getInstance().dnsRefreshRequestTime = dnsRefreshRequestTime.orElse(null);
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
/** Build the resource, nullifying empty strings and sets and setting defaults. */
|
||||
@Override
|
||||
public T build() {
|
||||
|
||||
+19
-5
@@ -44,6 +44,8 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static boolean useUncachedForTest = false;
|
||||
|
||||
public enum PrimaryDatabase {
|
||||
CLOUD_SQL,
|
||||
DATASTORE
|
||||
@@ -85,7 +87,10 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
|
||||
SQL_ONLY(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY),
|
||||
|
||||
/** Toggles SQL Sequence based allocateId */
|
||||
SEQUENCE_BASED_ALLOCATE_ID(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY);
|
||||
SEQUENCE_BASED_ALLOCATE_ID(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY),
|
||||
|
||||
/** Use SQL-based Nordn upload flow instead of the pull queue-based one. */
|
||||
NORDN_SQL(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY);
|
||||
|
||||
private final PrimaryDatabase primaryDatabase;
|
||||
private final boolean isReadOnly;
|
||||
@@ -164,7 +169,9 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
|
||||
MigrationState.SQL_ONLY,
|
||||
MigrationState.SQL_PRIMARY_READ_ONLY,
|
||||
MigrationState.SQL_PRIMARY)
|
||||
.putAll(MigrationState.SQL_ONLY, MigrationState.SEQUENCE_BASED_ALLOCATE_ID);
|
||||
.putAll(MigrationState.SQL_ONLY, MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
|
||||
.putAll(MigrationState.SEQUENCE_BASED_ALLOCATE_ID, MigrationState.NORDN_SQL)
|
||||
.putAll(MigrationState.NORDN_SQL, MigrationState.SEQUENCE_BASED_ALLOCATE_ID);
|
||||
|
||||
// In addition, we can always transition from a state to itself (useful when updating the map).
|
||||
Arrays.stream(MigrationState.values()).forEach(state -> builder.put(state, state));
|
||||
@@ -181,8 +188,8 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
|
||||
public TimedTransitionProperty<MigrationState> migrationTransitions =
|
||||
TimedTransitionProperty.withInitialValue(MigrationState.DATASTORE_ONLY);
|
||||
|
||||
// Required for Objectify initialization
|
||||
private DatabaseMigrationStateSchedule() {}
|
||||
// Required for Hibernate initialization
|
||||
protected DatabaseMigrationStateSchedule() {}
|
||||
|
||||
@VisibleForTesting
|
||||
public DatabaseMigrationStateSchedule(
|
||||
@@ -205,6 +212,11 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
|
||||
CACHE.invalidateAll();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void useUncachedForTest() {
|
||||
useUncachedForTest = true;
|
||||
}
|
||||
|
||||
/** Loads the currently-set migration schedule from the cache, or the default if none exists. */
|
||||
public static TimedTransitionProperty<MigrationState> get() {
|
||||
return CACHE.get(DatabaseMigrationStateSchedule.class);
|
||||
@@ -212,7 +224,9 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
|
||||
|
||||
/** Returns the database migration status at the given time. */
|
||||
public static MigrationState getValueAtTime(DateTime dateTime) {
|
||||
return get().getValueAtTime(dateTime);
|
||||
return useUncachedForTest
|
||||
? getUncached().getValueAtTime(dateTime)
|
||||
: get().getValueAtTime(dateTime);
|
||||
}
|
||||
|
||||
/** Loads the currently-set migration schedule from SQL, or the default if none exists. */
|
||||
|
||||
@@ -24,6 +24,7 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.UpdateAutoTimestampEntity;
|
||||
import google.registry.persistence.VKey;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
@@ -47,7 +48,6 @@ public class User extends UpdateAutoTimestampEntity implements Buildable {
|
||||
private Long id;
|
||||
|
||||
/** GAIA ID associated with the user in question. */
|
||||
@Column(nullable = false)
|
||||
private String gaiaId;
|
||||
|
||||
/** Email address of the user in question. */
|
||||
@@ -118,6 +118,11 @@ public class User extends UpdateAutoTimestampEntity implements Buildable {
|
||||
return new Builder(clone(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VKey<User> createVKey() {
|
||||
return VKey.create(User.class, getId());
|
||||
}
|
||||
|
||||
/** Builder for constructing immutable {@link User} objects. */
|
||||
public static class Builder extends Buildable.Builder<User> {
|
||||
|
||||
@@ -129,7 +134,6 @@ public class User extends UpdateAutoTimestampEntity implements Buildable {
|
||||
|
||||
@Override
|
||||
public User build() {
|
||||
checkArgumentNotNull(getInstance().gaiaId, "Gaia ID cannot be null");
|
||||
checkArgumentNotNull(getInstance().emailAddress, "Email address cannot be null");
|
||||
checkArgumentNotNull(getInstance().userRoles, "User roles cannot be null");
|
||||
return super.build();
|
||||
|
||||
@@ -58,7 +58,6 @@ import org.joda.time.DateTime;
|
||||
@Index(columnList = "techContact"),
|
||||
@Index(columnList = "tld"),
|
||||
@Index(columnList = "registrantContact"),
|
||||
@Index(columnList = "dnsRefreshRequestTime"),
|
||||
@Index(columnList = "lordnPhase"),
|
||||
@Index(columnList = "billing_recurrence_id"),
|
||||
@Index(columnList = "transfer_billing_event_id"),
|
||||
@@ -200,7 +199,6 @@ public class Domain extends DomainBase implements ForeignKeyedEppResource {
|
||||
.setSubordinateHosts(domainBase.getSubordinateHosts())
|
||||
.setStatusValues(domainBase.getStatusValues())
|
||||
.setTransferData(domainBase.getTransferData())
|
||||
.setDnsRefreshRequestTime(domainBase.getDnsRefreshRequestTime())
|
||||
.setLordnPhase(domainBase.getLordnPhase())
|
||||
.setCurrentPackageToken(domainBase.getCurrentPackageToken().orElse(null));
|
||||
}
|
||||
|
||||
@@ -274,13 +274,6 @@ public class DomainBase extends EppResource
|
||||
return lordnPhase;
|
||||
}
|
||||
|
||||
@Access(AccessType.PROPERTY)
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "dnsRefreshRequestTime")
|
||||
private DateTime getInternalDnsRefreshRequestTime() {
|
||||
return getDnsRefreshRequestTime().orElse(null);
|
||||
}
|
||||
|
||||
public ImmutableSet<String> getSubordinateHosts() {
|
||||
return nullToEmptyImmutableCopy(subordinateHosts);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ import javax.persistence.Table;
|
||||
@Index(columnList = "creationTime"),
|
||||
@Index(columnList = "deletionTime"),
|
||||
@Index(columnList = "currentSponsorRegistrarId"),
|
||||
@Index(columnList = "dnsRefreshRequestTime")
|
||||
})
|
||||
@ExternalMessagingName("host")
|
||||
@WithVKey(String.class)
|
||||
@@ -94,7 +93,6 @@ public class Host extends HostBase implements ForeignKeyedEppResource {
|
||||
.setPersistedCurrentSponsorRegistrarId(hostBase.getPersistedCurrentSponsorRegistrarId())
|
||||
.setRepoId(hostBase.getRepoId())
|
||||
.setSuperordinateDomain(hostBase.getSuperordinateDomain())
|
||||
.setDnsRefreshRequestTime(hostBase.getDnsRefreshRequestTime())
|
||||
.setStatusValues(hostBase.getStatusValues());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -86,13 +85,6 @@ public class HostBase extends EppResource {
|
||||
*/
|
||||
DateTime lastSuperordinateChange;
|
||||
|
||||
@Access(AccessType.PROPERTY)
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "dnsRefreshRequestTime")
|
||||
private DateTime getInternalDnsRefreshRequestTime() {
|
||||
return getDnsRefreshRequestTime().orElse(null);
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return hostName;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ import com.google.common.base.Strings;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.util.RequestStatusChecker;
|
||||
import google.registry.util.RequestStatusCheckerImpl;
|
||||
import java.io.Serializable;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
@@ -70,8 +68,7 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
enum LockState {
|
||||
IN_USE,
|
||||
FREE,
|
||||
TIMED_OUT,
|
||||
OWNER_DIED
|
||||
TIMED_OUT
|
||||
}
|
||||
|
||||
@VisibleForTesting static LockMetrics lockMetrics = new LockMetrics();
|
||||
@@ -79,17 +76,6 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
/** The name of the locked resource. */
|
||||
@Transient @Id String lockId;
|
||||
|
||||
/**
|
||||
* Unique log ID of the request that owns this lock.
|
||||
*
|
||||
* <p>When that request is no longer running (is finished), the lock can be considered implicitly
|
||||
* released.
|
||||
*
|
||||
* <p>See {@link RequestStatusCheckerImpl#getLogId} for details about how it's created in
|
||||
* practice.
|
||||
*/
|
||||
@Column String requestLogId;
|
||||
|
||||
/** When the lock can be considered implicitly released. */
|
||||
@Column(nullable = false)
|
||||
DateTime expirationTime;
|
||||
@@ -124,7 +110,6 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
private static Lock create(
|
||||
String resourceName,
|
||||
String scope,
|
||||
String requestLogId,
|
||||
DateTime acquiredTime,
|
||||
Duration leaseLength) {
|
||||
checkArgument(!Strings.isNullOrEmpty(resourceName), "resourceName cannot be null or empty");
|
||||
@@ -132,7 +117,6 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
// Add the scope to the Lock's id so that it is unique for locks acquiring the same resource
|
||||
// across different TLDs.
|
||||
instance.lockId = makeLockId(resourceName, scope);
|
||||
instance.requestLogId = requestLogId;
|
||||
instance.expirationTime = acquiredTime.plus(leaseLength);
|
||||
instance.acquiredTime = acquiredTime;
|
||||
instance.resourceName = resourceName;
|
||||
@@ -172,18 +156,13 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
switch (acquireResult.lockState()) {
|
||||
case IN_USE:
|
||||
logger.atInfo().log(
|
||||
"Existing lock by request %s is still valid now %s (until %s) lock: %s",
|
||||
lock.requestLogId, now, lock.expirationTime, lock.lockId);
|
||||
"Existing lock by request is still valid now %s (until %s) lock: %s",
|
||||
now, lock.expirationTime, lock.lockId);
|
||||
break;
|
||||
case TIMED_OUT:
|
||||
logger.atInfo().log(
|
||||
"Existing lock by request %s is timed out now %s (was valid until %s) lock: %s",
|
||||
lock.requestLogId, now, lock.expirationTime, lock.lockId);
|
||||
break;
|
||||
case OWNER_DIED:
|
||||
logger.atInfo().log(
|
||||
"Existing lock is valid now %s (until %s), but owner (%s) isn't running lock: %s",
|
||||
now, lock.expirationTime, lock.requestLogId, lock.lockId);
|
||||
"Existing lock by request is timed out now %s (was valid until %s) lock: %s",
|
||||
now, lock.expirationTime, lock.lockId);
|
||||
break;
|
||||
case FREE:
|
||||
// There was no existing lock
|
||||
@@ -203,11 +182,7 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
|
||||
/** Try to acquire a lock. Returns absent if it can't be acquired. */
|
||||
public static Optional<Lock> acquire(
|
||||
String resourceName,
|
||||
@Nullable String tld,
|
||||
Duration leaseLength,
|
||||
RequestStatusChecker requestStatusChecker,
|
||||
boolean checkThreadRunning) {
|
||||
String resourceName, @Nullable String tld, Duration leaseLength) {
|
||||
String scope = tld != null ? tld : GLOBAL;
|
||||
Supplier<AcquireResult> lockAcquirer =
|
||||
() -> {
|
||||
@@ -219,22 +194,19 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
.orElse(null);
|
||||
if (lock != null) {
|
||||
logger.atInfo().log(
|
||||
"Loaded existing lock: %s for request: %s", lock.lockId, lock.requestLogId);
|
||||
"Loaded existing lock: %s for resource: %s", lock.lockId, lock.resourceName);
|
||||
}
|
||||
LockState lockState;
|
||||
if (lock == null) {
|
||||
lockState = LockState.FREE;
|
||||
} else if (isAtOrAfter(now, lock.expirationTime)) {
|
||||
lockState = LockState.TIMED_OUT;
|
||||
} else if (checkThreadRunning && !requestStatusChecker.isRunning(lock.requestLogId)) {
|
||||
lockState = LockState.OWNER_DIED;
|
||||
} else {
|
||||
lockState = LockState.IN_USE;
|
||||
return AcquireResult.create(now, lock, null, lockState);
|
||||
}
|
||||
|
||||
Lock newLock =
|
||||
create(resourceName, scope, requestStatusChecker.getLogId(), now, leaseLength);
|
||||
Lock newLock = create(resourceName, scope, now, leaseLength);
|
||||
tm().put(newLock);
|
||||
|
||||
return AcquireResult.create(now, lock, newLock, lockState);
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.SftpProgressMonitor;
|
||||
import dagger.Lazy;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.gcs.GcsUtils;
|
||||
import google.registry.keyring.api.KeyModule.Key;
|
||||
@@ -56,7 +57,6 @@ import google.registry.request.RequestParameters;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.TeeOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -131,8 +131,7 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
|
||||
prefix.ifPresent(s -> params.put(RdeModule.PARAM_PREFIX, s));
|
||||
cloudTasksUtils.enqueue(
|
||||
RDE_REPORT_QUEUE,
|
||||
cloudTasksUtils.createPostTask(
|
||||
RdeReportAction.PATH, Service.BACKEND.getServiceId(), params));
|
||||
cloudTasksUtils.createPostTask(RdeReportAction.PATH, Service.BACKEND, params));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
@@ -37,7 +38,6 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.IOException;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.Duration;
|
||||
@@ -140,7 +140,7 @@ public class GenerateInvoicesAction implements Runnable {
|
||||
ReportingModule.BEAM_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
PublishInvoicesAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
ReportingModule.PARAM_JOB_ID,
|
||||
jobId,
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.google.api.services.dataflow.model.Job;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.reporting.ReportingModule;
|
||||
import google.registry.request.Action;
|
||||
@@ -33,7 +34,6 @@ import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.IOException;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.YearMonth;
|
||||
@@ -127,7 +127,7 @@ public class PublishInvoicesAction implements Runnable {
|
||||
BillingModule.CRON_QUEUE,
|
||||
cloudTasksUtils.createPostTask(
|
||||
CopyDetailReportsAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(PARAM_YEAR_MONTH, yearMonth.toString())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.bigquery.BigqueryJobFailureException;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.reporting.icann.IcannReportingModule.ReportType;
|
||||
@@ -34,7 +35,6 @@ import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.SendEmailService;
|
||||
@@ -123,7 +123,7 @@ public final class IcannReportingStagingAction implements Runnable {
|
||||
CRON_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
IcannReportingUploadAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
null,
|
||||
Duration.standardMinutes(2)));
|
||||
return null;
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.keyring.api.KeyModule.Key;
|
||||
@@ -37,7 +38,6 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.IOException;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.Duration;
|
||||
@@ -135,7 +135,7 @@ public class GenerateSpec11ReportAction implements Runnable {
|
||||
ReportingModule.BEAM_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
PublishSpec11ReportAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
ReportingModule.PARAM_JOB_ID,
|
||||
jobId,
|
||||
|
||||
@@ -39,8 +39,6 @@ import google.registry.request.HttpException.UnsupportedMediaTypeException;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.request.lock.LockHandlerImpl;
|
||||
import google.registry.util.RequestStatusChecker;
|
||||
import google.registry.util.RequestStatusCheckerImpl;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -192,18 +190,6 @@ public final class RequestModule {
|
||||
return lockHandler;
|
||||
}
|
||||
|
||||
@Provides
|
||||
static RequestStatusChecker provideRequestStatusChecker(
|
||||
RequestStatusCheckerImpl requestStatusChecker) {
|
||||
return requestStatusChecker;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@RequestLogId
|
||||
static String provideRequestLogId(RequestStatusChecker requestStatusChecker) {
|
||||
return requestStatusChecker.getLogId();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JsonPayload
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import javax.inject.Qualifier;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
@@ -30,15 +31,26 @@ import javax.inject.Singleton;
|
||||
public class AuthModule {
|
||||
|
||||
private static final String IAP_ISSUER_URL = "https://cloud.google.com/iap";
|
||||
private static final String SA_ISSUER_URL = "https://accounts.google.com";
|
||||
|
||||
/** Provides the custom authentication mechanisms (including OAuth). */
|
||||
@Provides
|
||||
ImmutableList<AuthenticationMechanism> provideApiAuthenticationMechanisms(
|
||||
OAuthAuthenticationMechanism oauthAuthenticationMechanism,
|
||||
IapHeaderAuthenticationMechanism iapHeaderAuthenticationMechanism) {
|
||||
return ImmutableList.of(oauthAuthenticationMechanism, iapHeaderAuthenticationMechanism);
|
||||
IapHeaderAuthenticationMechanism iapHeaderAuthenticationMechanism,
|
||||
ServiceAccountAuthenticationMechanism serviceAccountAuthenticationMechanism) {
|
||||
return ImmutableList.of(
|
||||
oauthAuthenticationMechanism,
|
||||
iapHeaderAuthenticationMechanism,
|
||||
serviceAccountAuthenticationMechanism);
|
||||
}
|
||||
|
||||
@Qualifier
|
||||
@interface IAP {}
|
||||
|
||||
@Qualifier
|
||||
@interface ServiceAccount {}
|
||||
|
||||
/** Provides the OAuthService instance. */
|
||||
@Provides
|
||||
OAuthService provideOauthService() {
|
||||
@@ -46,10 +58,18 @@ public class AuthModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@IAP
|
||||
@Singleton
|
||||
TokenVerifier provideTokenVerifier(
|
||||
@Config("projectId") String projectId, @Config("projectIdNumber") long projectIdNumber) {
|
||||
String audience = String.format("/projects/%d/apps/%s", projectIdNumber, projectId);
|
||||
return TokenVerifier.newBuilder().setAudience(audience).setIssuer(IAP_ISSUER_URL).build();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ServiceAccount
|
||||
@Singleton
|
||||
TokenVerifier provideServiceAccountTokenVerifier(@Config("projectId") String projectId) {
|
||||
return TokenVerifier.newBuilder().setAudience(projectId).setIssuer(SA_ISSUER_URL).build();
|
||||
}
|
||||
}
|
||||
|
||||
+10
-37
@@ -14,15 +14,11 @@
|
||||
|
||||
package google.registry.request.auth;
|
||||
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature;
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import google.registry.request.auth.AuthModule.IAP;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -37,41 +33,22 @@ import javax.servlet.http.HttpServletRequest;
|
||||
* @see <a href="https://cloud.google.com/iap/docs/signed-headers-howto">the documentation on GCP
|
||||
* IAP's signed headers for more information.</a>
|
||||
*/
|
||||
public class IapHeaderAuthenticationMechanism implements AuthenticationMechanism {
|
||||
public class IapHeaderAuthenticationMechanism extends IdTokenAuthenticationBase {
|
||||
|
||||
private static final String ID_TOKEN_HEADER_NAME = "X-Goog-IAP-JWT-Assertion";
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
// A workaround that allows "use" of the IAP-based authenticator when running local testing, i.e.
|
||||
// the RegistryTestServer
|
||||
private static Optional<User> userForTesting = Optional.empty();
|
||||
|
||||
private final TokenVerifier tokenVerifier;
|
||||
|
||||
@Inject
|
||||
public IapHeaderAuthenticationMechanism(TokenVerifier tokenVerifier) {
|
||||
this.tokenVerifier = tokenVerifier;
|
||||
public IapHeaderAuthenticationMechanism(@IAP TokenVerifier tokenVerifier) {
|
||||
super(tokenVerifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResult authenticate(HttpServletRequest request) {
|
||||
if (RegistryEnvironment.get().equals(RegistryEnvironment.UNITTEST)
|
||||
&& userForTesting.isPresent()) {
|
||||
return AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userForTesting.get()));
|
||||
}
|
||||
String rawIdToken = request.getHeader(ID_TOKEN_HEADER_NAME);
|
||||
if (rawIdToken == null) {
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
}
|
||||
JsonWebSignature token;
|
||||
try {
|
||||
token = tokenVerifier.verify(rawIdToken);
|
||||
} catch (TokenVerifier.VerificationException e) {
|
||||
logger.atInfo().withCause(e).log("Error when verifying access token");
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
}
|
||||
String emailAddress = (String) token.getPayload().get("email");
|
||||
String rawTokenFromRequest(HttpServletRequest request) {
|
||||
return request.getHeader(ID_TOKEN_HEADER_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
AuthResult authResultFromEmail(String emailAddress) {
|
||||
Optional<User> maybeUser = UserDao.loadUser(emailAddress);
|
||||
if (!maybeUser.isPresent()) {
|
||||
logger.atInfo().log("No user found for email address %s", emailAddress);
|
||||
@@ -80,8 +57,4 @@ public class IapHeaderAuthenticationMechanism implements AuthenticationMechanism
|
||||
return AuthResult.create(AuthLevel.USER, UserAuthInfo.create(maybeUser.get()));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void setUserAuthInfoForTestServer(@Nullable User user) {
|
||||
userForTesting = Optional.ofNullable(user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2022 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.request.auth;
|
||||
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature;
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.model.console.User;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public abstract class IdTokenAuthenticationBase implements AuthenticationMechanism {
|
||||
|
||||
public static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
// A workaround that allows "use" of the IAP-based authenticator when running local testing, i.e.
|
||||
// the RegistryTestServer
|
||||
private static Optional<User> userForTesting = Optional.empty();
|
||||
|
||||
private final TokenVerifier tokenVerifier;
|
||||
|
||||
public IdTokenAuthenticationBase(TokenVerifier tokenVerifier) {
|
||||
this.tokenVerifier = tokenVerifier;
|
||||
}
|
||||
|
||||
abstract String rawTokenFromRequest(HttpServletRequest request);
|
||||
|
||||
abstract AuthResult authResultFromEmail(String email);
|
||||
|
||||
@Override
|
||||
public AuthResult authenticate(HttpServletRequest request) {
|
||||
if (RegistryEnvironment.get().equals(RegistryEnvironment.UNITTEST)
|
||||
&& userForTesting.isPresent()) {
|
||||
return AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userForTesting.get()));
|
||||
}
|
||||
String rawIdToken = rawTokenFromRequest(request);
|
||||
if (rawIdToken == null) {
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
}
|
||||
JsonWebSignature token;
|
||||
try {
|
||||
token = tokenVerifier.verify(rawIdToken);
|
||||
} catch (Exception e) {
|
||||
logger.atInfo().withCause(e).log("Error when verifying access token");
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
}
|
||||
String emailAddress = (String) token.getPayload().get("email");
|
||||
return authResultFromEmail(emailAddress);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void setUserAuthInfoForTestServer(@Nullable User user) {
|
||||
userForTesting = Optional.ofNullable(user);
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
// Copyright 2023 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.request.auth;
|
||||
|
||||
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||
import static google.registry.request.auth.AuthLevel.APP;
|
||||
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.request.auth.AuthModule.ServiceAccount;
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* A way to authenticate HTTP requests signed by Service Account
|
||||
*
|
||||
* <p>Currently used by cloud scheduler service account
|
||||
*/
|
||||
public class ServiceAccountAuthenticationMechanism extends IdTokenAuthenticationBase {
|
||||
|
||||
private final String cloudSchedulerEmailPrefix;
|
||||
private static final String BEARER_PREFIX = "Bearer ";
|
||||
|
||||
@Inject
|
||||
public ServiceAccountAuthenticationMechanism(
|
||||
@ServiceAccount TokenVerifier tokenVerifier,
|
||||
@Config("cloudSchedulerServiceAccountEmail") String cloudSchedulerEmailPrefix) {
|
||||
|
||||
super(tokenVerifier);
|
||||
this.cloudSchedulerEmailPrefix = cloudSchedulerEmailPrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
String rawTokenFromRequest(HttpServletRequest request) {
|
||||
String rawToken = request.getHeader(AUTHORIZATION);
|
||||
if (rawToken != null && rawToken.startsWith(BEARER_PREFIX)) {
|
||||
return rawToken.substring(BEARER_PREFIX.length());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
AuthResult authResultFromEmail(String emailAddress) {
|
||||
if (emailAddress.equals(cloudSchedulerEmailPrefix)) {
|
||||
return AuthResult.create(APP);
|
||||
} else {
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import google.registry.model.server.Lock;
|
||||
import google.registry.util.AppEngineTimeLimiter;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.RequestStatusChecker;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -48,12 +47,10 @@ public class LockHandlerImpl implements LockHandler {
|
||||
/** Fudge factor to make sure we kill threads before a lock actually expires. */
|
||||
private static final Duration LOCK_TIMEOUT_FUDGE = Duration.standardSeconds(5);
|
||||
|
||||
private final RequestStatusChecker requestStatusChecker;
|
||||
private final Clock clock;
|
||||
|
||||
@Inject
|
||||
public LockHandlerImpl(RequestStatusChecker requestStatusChecker, Clock clock) {
|
||||
this.requestStatusChecker = requestStatusChecker;
|
||||
public LockHandlerImpl(Clock clock) {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@@ -114,7 +111,7 @@ public class LockHandlerImpl implements LockHandler {
|
||||
/** Allows injection of mock Lock in tests. */
|
||||
@VisibleForTesting
|
||||
Optional<Lock> acquire(String lockName, @Nullable String tld, Duration leaseLength) {
|
||||
return Lock.acquire(lockName, tld, leaseLength, requestStatusChecker, true);
|
||||
return Lock.acquire(lockName, tld, leaseLength);
|
||||
}
|
||||
|
||||
private interface LockAcquirer {
|
||||
|
||||
@@ -49,7 +49,6 @@ U+011F # LATIN SMALL LETTER G WITH BREVE
|
||||
U+01E7 # LATIN SMALL LETTER G WITH CARON
|
||||
U+0121 # LATIN SMALL LETTER G WITH DOT ABOVE
|
||||
U+0123 # LATIN SMALL LETTER G WITH CEDILLA
|
||||
U+01E5 # LATIN SMALL LETTER G WITH STROKE
|
||||
U+0068 # LATIN SMALL LETTER H
|
||||
U+0127 # LATIN SMALL LETTER H WITH STROKE
|
||||
U+0069 # LATIN SMALL LETTER I
|
||||
|
||||
@@ -66,7 +66,12 @@ public final class LordnTaskUtils {
|
||||
}
|
||||
|
||||
/** Returns the corresponding CSV LORDN line for a sunrise domain. */
|
||||
public static String getCsvLineForSunriseDomain(Domain domain, DateTime transactionTime) {
|
||||
public static String getCsvLineForSunriseDomain(Domain domain) {
|
||||
return getCsvLineForSunriseDomain(domain, domain.getCreationTime());
|
||||
}
|
||||
|
||||
// TODO: Merge into the function above after pull queue migration.
|
||||
private static String getCsvLineForSunriseDomain(Domain domain, DateTime transactionTime) {
|
||||
return Joiner.on(',')
|
||||
.join(
|
||||
domain.getRepoId(),
|
||||
@@ -77,7 +82,12 @@ public final class LordnTaskUtils {
|
||||
}
|
||||
|
||||
/** Returns the corresponding CSV LORDN line for a claims domain. */
|
||||
public static String getCsvLineForClaimsDomain(Domain domain, DateTime transactionTime) {
|
||||
public static String getCsvLineForClaimsDomain(Domain domain) {
|
||||
return getCsvLineForClaimsDomain(domain, domain.getCreationTime());
|
||||
}
|
||||
|
||||
// TODO: Merge into the function above after pull queue migration.
|
||||
private static String getCsvLineForClaimsDomain(Domain domain, DateTime transactionTime) {
|
||||
return Joiner.on(',')
|
||||
.join(
|
||||
domain.getRepoId(),
|
||||
@@ -100,16 +110,8 @@ public final class LordnTaskUtils {
|
||||
private LordnTaskUtils() {}
|
||||
|
||||
public enum LordnPhase {
|
||||
SUNRISE(QUEUE_SUNRISE),
|
||||
|
||||
CLAIMS(QUEUE_CLAIMS),
|
||||
|
||||
NONE(null);
|
||||
|
||||
final String queue;
|
||||
|
||||
LordnPhase(String queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
SUNRISE,
|
||||
CLAIMS,
|
||||
NONE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,13 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.net.HttpHeaders.LOCATION;
|
||||
import static com.google.common.net.MediaType.CSV_UTF_8;
|
||||
import static google.registry.persistence.transaction.QueryComposer.Comparator.EQ;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.request.UrlConnectionUtils.getResponseBytes;
|
||||
import static google.registry.tmch.LordnTaskUtils.COLUMNS_CLAIMS;
|
||||
import static google.registry.tmch.LordnTaskUtils.COLUMNS_SUNRISE;
|
||||
import static google.registry.tmch.LordnTaskUtils.getCsvLineForClaimsDomain;
|
||||
import static google.registry.tmch.LordnTaskUtils.getCsvLineForSunriseDomain;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_ACCEPTED;
|
||||
@@ -33,6 +37,7 @@ import com.google.appengine.api.taskqueue.TaskHandle;
|
||||
import com.google.appengine.api.taskqueue.TransientFailureException;
|
||||
import com.google.apphosting.api.DeadlineExceededException;
|
||||
import com.google.cloud.tasks.v2.Task;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -41,7 +46,9 @@ import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
@@ -49,8 +56,8 @@ import google.registry.request.RequestParameters;
|
||||
import google.registry.request.UrlConnectionService;
|
||||
import google.registry.request.UrlConnectionUtils;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.UrlConnectionException;
|
||||
import java.io.IOException;
|
||||
@@ -59,6 +66,7 @@ import java.net.URL;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
@@ -81,9 +89,11 @@ import org.joda.time.Duration;
|
||||
public final class NordnUploadAction implements Runnable {
|
||||
|
||||
static final String PATH = "/_dr/task/nordnUpload";
|
||||
static final String LORDN_PHASE_PARAM = "lordn-phase";
|
||||
static final String LORDN_PHASE_PARAM = "lordnPhase";
|
||||
// TODO: Delete after migrating off of pull queue.
|
||||
static final String PULL_QUEUE_PARAM = "pullQueue";
|
||||
|
||||
private static final int QUEUE_BATCH_SIZE = 1000;
|
||||
private static final int BATCH_SIZE = 1000;
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private static final Duration LEASE_PERIOD = Duration.standardHours(1);
|
||||
|
||||
@@ -100,31 +110,102 @@ public final class NordnUploadAction implements Runnable {
|
||||
@Inject LordnRequestInitializer lordnRequestInitializer;
|
||||
@Inject UrlConnectionService urlConnectionService;
|
||||
|
||||
@Inject @Config("tmchMarksdbUrl") String tmchMarksdbUrl;
|
||||
@Inject @Parameter(LORDN_PHASE_PARAM) String phase;
|
||||
@Inject @Parameter(RequestParameters.PARAM_TLD) String tld;
|
||||
@Inject
|
||||
@Config("tmchMarksdbUrl")
|
||||
String tmchMarksdbUrl;
|
||||
|
||||
@Inject
|
||||
@Parameter(LORDN_PHASE_PARAM)
|
||||
String phase;
|
||||
|
||||
@Inject
|
||||
@Parameter(RequestParameters.PARAM_TLD)
|
||||
String tld;
|
||||
|
||||
@Inject
|
||||
@Parameter(PULL_QUEUE_PARAM)
|
||||
Optional<Boolean> usePullQueue;
|
||||
|
||||
@Inject CloudTasksUtils cloudTasksUtils;
|
||||
|
||||
@Inject NordnUploadAction() {}
|
||||
@Inject
|
||||
NordnUploadAction() {}
|
||||
|
||||
/**
|
||||
* These LORDN parameter names correspond to the relative paths in LORDN URLs and cannot be
|
||||
* changed on our end.
|
||||
*/
|
||||
private static final String PARAM_LORDN_PHASE_SUNRISE = "sunrise";
|
||||
private static final String PARAM_LORDN_PHASE_SUNRISE =
|
||||
Ascii.toLowerCase(LordnPhase.SUNRISE.toString());
|
||||
|
||||
private static final String PARAM_LORDN_PHASE_CLAIMS = "claims";
|
||||
private static final String PARAM_LORDN_PHASE_CLAIMS =
|
||||
Ascii.toLowerCase(LordnPhase.CLAIMS.toString());
|
||||
|
||||
/** How long to wait before attempting to verify an upload by fetching the log. */
|
||||
private static final Duration VERIFY_DELAY = Duration.standardMinutes(30);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
processLordnTasks();
|
||||
} catch (IOException | GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
if (usePullQueue.orElse(false)) {
|
||||
try {
|
||||
processLordnTasks();
|
||||
} catch (IOException | GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
checkArgument(
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE) || phase.equals(PARAM_LORDN_PHASE_CLAIMS),
|
||||
"Invalid phase specified to NordnUploadAction: %s.",
|
||||
phase);
|
||||
tm().transact(
|
||||
() -> {
|
||||
// Note here that we load all domains pending Nordn in one batch, which should not
|
||||
// be a problem for the rate of domain registration that we see. If we anticipate
|
||||
// a peak in claims during TLD launch (sunrise is NOT first-come-first-serve, so
|
||||
// there should be no expectation of a peak during it), we can consider temporarily
|
||||
// increasing the frequency of Nordn upload to reduce the size of each batch.
|
||||
//
|
||||
// We did not further divide the domains into smaller batches because the
|
||||
// read-upload-write operation per small batch needs to be inside a single
|
||||
// transaction to prevent race conditions, and running several uploads in rapid
|
||||
// sucession will likely overwhelm the MarksDB upload server, which recommands a
|
||||
// maximum upload frequency of every 3 hours.
|
||||
//
|
||||
// See:
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-regext-tmch-func-spec-01#section-5.2.3.3
|
||||
List<Domain> domains =
|
||||
tm().createQueryComposer(Domain.class)
|
||||
.where("lordnPhase", EQ, LordnPhase.valueOf(Ascii.toUpperCase(phase)))
|
||||
.where("tld", EQ, tld)
|
||||
.orderBy("creationTime")
|
||||
.list();
|
||||
if (domains.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
StringBuilder csv = new StringBuilder();
|
||||
ImmutableList.Builder<Domain> newDomains = new ImmutableList.Builder<>();
|
||||
|
||||
domains.forEach(
|
||||
domain -> {
|
||||
if (phase.equals(PARAM_LORDN_PHASE_SUNRISE)) {
|
||||
csv.append(getCsvLineForSunriseDomain(domain)).append('\n');
|
||||
} else {
|
||||
csv.append(getCsvLineForClaimsDomain(domain)).append('\n');
|
||||
}
|
||||
Domain newDomain = domain.asBuilder().setLordnPhase(LordnPhase.NONE).build();
|
||||
newDomains.add(newDomain);
|
||||
});
|
||||
String columns =
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE) ? COLUMNS_SUNRISE : COLUMNS_CLAIMS;
|
||||
String header =
|
||||
String.format("1,%s,%d\n%s\n", clock.nowUtc(), domains.size(), columns);
|
||||
try {
|
||||
uploadCsvToLordn(String.format("/LORDN/%s/%s", tld, phase), header + csv);
|
||||
} catch (IOException | GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
tm().updateAll(newDomains.build());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +239,7 @@ public final class NordnUploadAction implements Runnable {
|
||||
queue.leaseTasks(
|
||||
LeaseOptions.Builder.withTag(tld)
|
||||
.leasePeriod(LEASE_PERIOD.getMillis(), TimeUnit.MILLISECONDS)
|
||||
.countLimit(QUEUE_BATCH_SIZE)),
|
||||
.countLimit(BATCH_SIZE)),
|
||||
TransientFailureException.class,
|
||||
DeadlineExceededException.class);
|
||||
if (tasks.isEmpty()) {
|
||||
@@ -171,7 +252,7 @@ public final class NordnUploadAction implements Runnable {
|
||||
private void processLordnTasks() throws IOException, GeneralSecurityException {
|
||||
checkArgument(
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE) || phase.equals(PARAM_LORDN_PHASE_CLAIMS),
|
||||
"Invalid phase specified to Nordn servlet: %s.",
|
||||
"Invalid phase specified to NordnUploadAction: %s.",
|
||||
phase);
|
||||
DateTime now = clock.nowUtc();
|
||||
Queue queue =
|
||||
@@ -184,12 +265,12 @@ public final class NordnUploadAction implements Runnable {
|
||||
// Note: This upload/task deletion isn't done atomically (it's not clear how one would do so
|
||||
// anyway). As a result, it is possible that the upload might succeed yet the deletion of
|
||||
// enqueued tasks might fail. If so, this would result in the same lines being uploaded to NORDN
|
||||
// across mulitple uploads. This is probably OK; all that we really cannot have is a missing
|
||||
// across multiple uploads. This is probably OK; all that we really cannot have is a missing
|
||||
// line.
|
||||
if (!tasks.isEmpty()) {
|
||||
String csvData = convertTasksToCsv(tasks, now, columns);
|
||||
uploadCsvToLordn(String.format("/LORDN/%s/%s", tld, phase), csvData);
|
||||
Lists.partition(tasks, QUEUE_BATCH_SIZE)
|
||||
Lists.partition(tasks, BATCH_SIZE)
|
||||
.forEach(
|
||||
batch ->
|
||||
retrier.callWithRetry(
|
||||
@@ -252,7 +333,7 @@ public final class NordnUploadAction implements Runnable {
|
||||
// The actionLogId is used to uniquely associate the verify task back to the upload task.
|
||||
return cloudTasksUtils.createPostTaskWithDelay(
|
||||
NordnVerifyAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put(NordnVerifyAction.NORDN_URL_PARAM, url.toString())
|
||||
.put(NordnVerifyAction.NORDN_LOG_ID_PARAM, actionLogId)
|
||||
|
||||
@@ -22,6 +22,7 @@ import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
|
||||
import google.registry.model.CacheUtils;
|
||||
@@ -55,6 +56,7 @@ public final class TmchCertificateAuthority {
|
||||
private static final String ROOT_CRT_PILOT_FILE = "icann-tmch-pilot.crt";
|
||||
private static final String CRL_FILE = "icann-tmch.crl";
|
||||
private static final String CRL_PILOT_FILE = "icann-tmch-pilot.crl";
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private final TmchCaMode tmchCaMode;
|
||||
private final Clock clock;
|
||||
@@ -142,8 +144,14 @@ public final class TmchCertificateAuthority {
|
||||
* @see X509Utils#verifyCrl
|
||||
*/
|
||||
public void updateCrl(String asciiCrl, String url) throws GeneralSecurityException {
|
||||
X509CRL crl = X509Utils.loadCrl(asciiCrl);
|
||||
X509Utils.verifyCrl(getAndValidateRoot(), getCrl(), crl, clock.nowUtc().toDate());
|
||||
X509CRL newCrl = X509Utils.loadCrl(asciiCrl);
|
||||
X509CRL oldCrl = null;
|
||||
try {
|
||||
oldCrl = getCrl();
|
||||
} catch (Exception e) {
|
||||
logger.atWarning().withCause(e).log("Old CRL is invalid, ignored during CRL update.");
|
||||
}
|
||||
X509Utils.verifyCrl(getAndValidateRoot(), oldCrl, newCrl, clock.nowUtc().toDate());
|
||||
TmchCrl.set(asciiCrl, url);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.tmch;
|
||||
|
||||
import static com.google.common.io.Resources.asByteSource;
|
||||
import static com.google.common.io.Resources.getResource;
|
||||
import static google.registry.request.RequestParameters.extractOptionalBooleanParameter;
|
||||
import static google.registry.request.RequestParameters.extractRequiredParameter;
|
||||
|
||||
import dagger.Module;
|
||||
@@ -25,6 +26,7 @@ import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.Parameter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
|
||||
@@ -64,4 +66,10 @@ public final class TmchModule {
|
||||
static String provideNordnLogId(HttpServletRequest req) {
|
||||
return extractRequiredParameter(req, NordnVerifyAction.NORDN_LOG_ID_PARAM);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter(NordnUploadAction.PULL_QUEUE_PARAM)
|
||||
static Optional<Boolean> provideUsePullQueue(HttpServletRequest req) {
|
||||
return extractOptionalBooleanParameter(req, NordnUploadAction.PULL_QUEUE_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright 2023 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;
|
||||
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.tools.params.KeyValueMapParameter.StringToRegistrarRoleMap;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Shared base class for commands that create or modify a {@link User}. */
|
||||
public abstract class CreateOrUpdateUserCommand extends ConfirmingCommand {
|
||||
|
||||
@Nullable
|
||||
@Parameter(names = "--email", description = "Email address of the user", required = true)
|
||||
String email;
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = "--admin",
|
||||
description = "Whether or not the user in question is an admin",
|
||||
arity = 1)
|
||||
private Boolean isAdmin;
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = "--global_role",
|
||||
description = "Global role, e.g. SUPPORT_LEAD, to apply to the user")
|
||||
private GlobalRole globalRole;
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = "--registrar_roles",
|
||||
converter = StringToRegistrarRoleMap.class,
|
||||
validateWith = StringToRegistrarRoleMap.class,
|
||||
description =
|
||||
"Comma-delimited mapping of registrar name to role that the user has on that registrar")
|
||||
private ImmutableMap<String, RegistrarRole> registrarRolesMap;
|
||||
|
||||
@Nullable
|
||||
abstract User getExistingUser(String email);
|
||||
|
||||
@Override
|
||||
protected final String execute() throws Exception {
|
||||
checkArgumentNotNull(email, "Email must be provided");
|
||||
tm().transact(this::executeInTransaction);
|
||||
return String.format("Saved user with email %s", email);
|
||||
}
|
||||
|
||||
private void executeInTransaction() {
|
||||
User user = getExistingUser(email);
|
||||
UserRoles.Builder userRolesBuilder =
|
||||
(user == null) ? new UserRoles.Builder() : user.getUserRoles().asBuilder();
|
||||
|
||||
Optional.ofNullable(globalRole).ifPresent(userRolesBuilder::setGlobalRole);
|
||||
Optional.ofNullable(registrarRolesMap).ifPresent(userRolesBuilder::setRegistrarRoles);
|
||||
Optional.ofNullable(isAdmin).ifPresent(userRolesBuilder::setIsAdmin);
|
||||
|
||||
User.Builder builder =
|
||||
(user == null) ? new User.Builder().setEmailAddress(email) : user.asBuilder();
|
||||
builder.setUserRoles(userRolesBuilder.build());
|
||||
User newUser = builder.build();
|
||||
UserDao.saveUser(newUser);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2023 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;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.beust.jcommander.Parameters;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Command to create a new User. */
|
||||
@Parameters(separators = " =", commandDescription = "Update a user account")
|
||||
public class CreateUserCommand extends CreateOrUpdateUserCommand {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
User getExistingUser(String email) {
|
||||
checkArgument(
|
||||
!UserDao.loadUser(email).isPresent(), "A user with email %s already exists", email);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2023 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;
|
||||
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Deletes a {@link User}. */
|
||||
@Parameters(separators = " =", commandDescription = "Delete a user account")
|
||||
public class DeleteUserCommand extends ConfirmingCommand {
|
||||
|
||||
@Nullable
|
||||
@Parameter(names = "--email", description = "Email address of the user", required = true)
|
||||
String email;
|
||||
|
||||
@Override
|
||||
protected String prompt() {
|
||||
checkArgumentNotNull(email, "Email must be provided");
|
||||
checkArgumentPresent(UserDao.loadUser(email), "Email does not correspond to a valid user");
|
||||
return String.format("Delete user with email %s?", email);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String execute() throws Exception {
|
||||
tm().transact(
|
||||
() -> {
|
||||
Optional<User> optionalUser = UserDao.loadUser(email);
|
||||
checkArgumentPresent(optionalUser, "Email no longer corresponds to a valid user");
|
||||
tm().delete(optionalUser.get());
|
||||
});
|
||||
return String.format("Deleted user with email %s", email);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STAT
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.batch.RelockDomainAction;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
@@ -34,7 +35,6 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.RegistryLockDao;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.StringGenerator;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -223,7 +223,7 @@ public final class DomainLockUtils {
|
||||
QUEUE_ASYNC_ACTIONS,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
RelockDomainAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
RelockDomainAction.OLD_UNLOCK_REVISION_ID_PARAM,
|
||||
String.valueOf(lockRevisionId),
|
||||
|
||||
@@ -28,11 +28,11 @@ import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.model.rde.RdeMode;
|
||||
import google.registry.rde.RdeStagingAction;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.tools.params.DateTimeParameter;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
@@ -122,7 +122,7 @@ final class GenerateEscrowDepositCommand implements Command {
|
||||
cloudTasksUtils.enqueue(
|
||||
RDE_REPORT_QUEUE,
|
||||
cloudTasksUtils.createPostTask(
|
||||
RdeStagingAction.PATH, Service.BACKEND.toString(), paramsBuilder.build()));
|
||||
RdeStagingAction.PATH, Service.BACKEND, paramsBuilder.build()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,10 +94,10 @@ final class GenerateLordnCommand implements Command {
|
||||
Domain domain) {
|
||||
String status = " ";
|
||||
if (domain.getLaunchNotice() == null && domain.getSmdId() != null) {
|
||||
sunriseCsv.add(LordnTaskUtils.getCsvLineForSunriseDomain(domain, domain.getCreationTime()));
|
||||
sunriseCsv.add(LordnTaskUtils.getCsvLineForSunriseDomain(domain));
|
||||
status = "S";
|
||||
} else if (domain.getLaunchNotice() != null || domain.getSmdId() != null) {
|
||||
claimsCsv.add(LordnTaskUtils.getCsvLineForClaimsDomain(domain, domain.getCreationTime()));
|
||||
claimsCsv.add(LordnTaskUtils.getCsvLineForClaimsDomain(domain));
|
||||
status = "C";
|
||||
}
|
||||
System.out.printf("%s[%s] ", domain.getDomainName(), status);
|
||||
|
||||
@@ -46,6 +46,7 @@ public final class RegistryTool {
|
||||
.put("create_registrar_groups", CreateRegistrarGroupsCommand.class)
|
||||
.put("create_reserved_list", CreateReservedListCommand.class)
|
||||
.put("create_tld", CreateTldCommand.class)
|
||||
.put("create_user", CreateUserCommand.class)
|
||||
.put("curl", CurlCommand.class)
|
||||
.put("delete_allocation_tokens", DeleteAllocationTokensCommand.class)
|
||||
.put("delete_domain", DeleteDomainCommand.class)
|
||||
@@ -53,6 +54,7 @@ public final class RegistryTool {
|
||||
.put("delete_premium_list", DeletePremiumListCommand.class)
|
||||
.put("delete_reserved_list", DeleteReservedListCommand.class)
|
||||
.put("delete_tld", DeleteTldCommand.class)
|
||||
.put("delete_user", DeleteUserCommand.class)
|
||||
.put("encrypt_escrow_deposit", EncryptEscrowDepositCommand.class)
|
||||
.put("enqueue_poll_message", EnqueuePollMessageCommand.class)
|
||||
.put("execute_epp", ExecuteEppCommand.class)
|
||||
@@ -110,6 +112,7 @@ public final class RegistryTool {
|
||||
.put("update_reserved_list", UpdateReservedListCommand.class)
|
||||
.put("update_server_locks", UpdateServerLocksCommand.class)
|
||||
.put("update_tld", UpdateTldCommand.class)
|
||||
.put("update_user", UpdateUserCommand.class)
|
||||
.put("upload_claims_list", UploadClaimsListCommand.class)
|
||||
.put("validate_escrow_deposit", ValidateEscrowDepositCommand.class)
|
||||
.put("validate_login_credentials", ValidateLoginCredentialsCommand.class)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 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;
|
||||
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||
|
||||
import com.beust.jcommander.Parameters;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Updates a user, assuming that the user in question already exists. */
|
||||
@Parameters(separators = " =", commandDescription = "Update a user account")
|
||||
public class UpdateUserCommand extends CreateOrUpdateUserCommand {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
User getExistingUser(String email) {
|
||||
return checkArgumentPresent(UserDao.loadUser(email), "User %s not found", email);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package google.registry.tools.params;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import java.util.Map;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
@@ -107,4 +108,18 @@ public abstract class KeyValueMapParameter<K, V>
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/** Combined converter/validator class for maps of registrar names to registrar roles. */
|
||||
public static class StringToRegistrarRoleMap extends KeyValueMapParameter<String, RegistrarRole> {
|
||||
|
||||
@Override
|
||||
protected String parseKey(String rawKey) {
|
||||
return rawKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegistrarRole parseValue(String rawValue) {
|
||||
return RegistrarRole.valueOf(rawValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.export.sheet.SyncRegistrarsSheetAction;
|
||||
import google.registry.flows.certs.CertificateChecker;
|
||||
@@ -58,7 +59,6 @@ import google.registry.ui.forms.FormException;
|
||||
import google.registry.ui.forms.FormFieldException;
|
||||
import google.registry.ui.server.RegistrarFormFields;
|
||||
import google.registry.ui.server.SendEmailUtils;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.CollectionUtils;
|
||||
import google.registry.util.DiffUtils;
|
||||
import java.util.HashSet;
|
||||
@@ -643,7 +643,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
cloudTasksUtils.enqueue(
|
||||
SyncRegistrarsSheetAction.QUEUE,
|
||||
cloudTasksUtils.createGetTask(
|
||||
SyncRegistrarsSheetAction.PATH, Service.BACKEND.toString(), ImmutableMultimap.of()));
|
||||
SyncRegistrarsSheetAction.PATH, Service.BACKEND, ImmutableMultimap.of()));
|
||||
}
|
||||
String environment = Ascii.toLowerCase(String.valueOf(RegistryEnvironment.get()));
|
||||
sendEmailUtils.sendEmail(
|
||||
|
||||
-6
@@ -23,12 +23,6 @@
|
||||
"helpText": "The exclusive upper bound of the operation window, in ISO 8601 format.",
|
||||
"is_optional": false
|
||||
},
|
||||
{
|
||||
"name": "shard",
|
||||
"label": "The exclusive upper bound of the operation window.",
|
||||
"helpText": "The exclusive upper bound of the operation window, in ISO 8601 format.",
|
||||
"is_optional": true
|
||||
},
|
||||
{
|
||||
"name": "isDryRun",
|
||||
"label": "Whether this job is a dry run.",
|
||||
|
||||
@@ -30,7 +30,6 @@ import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.util.CapturingLogHandler;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.JdkLoggerConfig;
|
||||
import java.util.logging.Level;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
+53
-44
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.util;
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -27,9 +27,11 @@ import com.google.cloud.tasks.v2.Task;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import google.registry.batch.CloudTasksUtils.SerializableCloudTasksClient;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.util.CloudTasksUtils.SerializableCloudTasksClient;
|
||||
import google.registry.util.Retrier;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
@@ -59,22 +61,22 @@ public class CloudTasksUtilsTest {
|
||||
|
||||
@Test
|
||||
void testSuccess_createGetTasks() {
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", "myservice", params);
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, params);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks() {
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", "myservice", params);
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", Service.BACKEND, params);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -84,42 +86,43 @@ public class CloudTasksUtilsTest {
|
||||
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withNullParams() {
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", "myservice", null);
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, null);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withNullParams() {
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", "myservice", null);
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", Service.BACKEND, null);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8)).isEmpty();
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withEmptyParams() {
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", "myservice", ImmutableMultimap.of());
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, ImmutableMultimap.of());
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withEmptyParams() {
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", "myservice", ImmutableMultimap.of());
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTask("/the/path", Service.BACKEND, ImmutableMultimap.of());
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8)).isEmpty();
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
@@ -128,12 +131,13 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithJitter("/the/path", "myservice", params, Optional.of(100));
|
||||
cloudTasksUtils.createGetTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.of(100));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
|
||||
Instant scheduleTime = Instant.ofEpochSecond(task.getScheduleTime().getSeconds());
|
||||
Instant lowerBoundTime = Instant.ofEpochMilli(clock.nowUtc().getMillis());
|
||||
@@ -147,11 +151,12 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithJitter("/the/path", "myservice", params, Optional.of(1));
|
||||
cloudTasksUtils.createPostTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.of(1));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -170,11 +175,11 @@ public class CloudTasksUtilsTest {
|
||||
void testSuccess_createPostTasks_withEmptyJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithJitter(
|
||||
"/the/path", "myservice", params, Optional.empty());
|
||||
"/the/path", Service.BACKEND, params, Optional.empty());
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -185,23 +190,25 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withEmptyJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithJitter("/the/path", "myservice", params, Optional.empty());
|
||||
cloudTasksUtils.createGetTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.empty());
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withZeroJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithJitter("/the/path", "myservice", params, Optional.of(0));
|
||||
cloudTasksUtils.createPostTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.of(0));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -212,12 +219,13 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withZeroJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithJitter("/the/path", "myservice", params, Optional.of(0));
|
||||
cloudTasksUtils.createGetTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.of(0));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@@ -225,12 +233,12 @@ public class CloudTasksUtilsTest {
|
||||
void testSuccess_createGetTasks_withDelay() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithDelay(
|
||||
"/the/path", "myservice", params, Duration.standardMinutes(10));
|
||||
"/the/path", Service.BACKEND, params, Duration.standardMinutes(10));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(Instant.ofEpochSecond(task.getScheduleTime().getSeconds()))
|
||||
.isEqualTo(Instant.ofEpochMilli(clock.nowUtc().plusMinutes(10).getMillis()));
|
||||
}
|
||||
@@ -239,11 +247,11 @@ public class CloudTasksUtilsTest {
|
||||
void testSuccess_createPostTasks_withDelay() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
"/the/path", "myservice", params, Duration.standardMinutes(10));
|
||||
"/the/path", Service.BACKEND, params, Duration.standardMinutes(10));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -260,7 +268,7 @@ public class CloudTasksUtilsTest {
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
cloudTasksUtils.createGetTaskWithDelay(
|
||||
"/the/path", "myservice", params, Duration.standardMinutes(-10)));
|
||||
"/the/path", Service.BACKEND, params, Duration.standardMinutes(-10)));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Negative duration is not supported.");
|
||||
}
|
||||
|
||||
@@ -271,18 +279,19 @@ public class CloudTasksUtilsTest {
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
cloudTasksUtils.createGetTaskWithDelay(
|
||||
"/the/path", "myservice", params, Duration.standardMinutes(-10)));
|
||||
"/the/path", Service.BACKEND, params, Duration.standardMinutes(-10)));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Negative duration is not supported.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withZeroDelay() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithDelay("/the/path", "myservice", params, Duration.ZERO);
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
"/the/path", Service.BACKEND, params, Duration.ZERO);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -293,12 +302,12 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withZeroDelay() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithDelay("/the/path", "myservice", params, Duration.ZERO);
|
||||
cloudTasksUtils.createGetTaskWithDelay("/the/path", Service.BACKEND, params, Duration.ZERO);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@@ -306,26 +315,26 @@ public class CloudTasksUtilsTest {
|
||||
void testFailure_illegalPath() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> cloudTasksUtils.createPostTask("the/path", "myservice", params));
|
||||
() -> cloudTasksUtils.createPostTask("the/path", Service.BACKEND, params));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> cloudTasksUtils.createPostTask(null, "myservice", params));
|
||||
() -> cloudTasksUtils.createPostTask(null, Service.BACKEND, params));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> cloudTasksUtils.createPostTask("", "myservice", params));
|
||||
() -> cloudTasksUtils.createPostTask("", Service.BACKEND, params));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_enqueueTask() {
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", "myservice", params);
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, params);
|
||||
cloudTasksUtils.enqueue("test-queue", task);
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_enqueueTasks_varargs() {
|
||||
Task task1 = cloudTasksUtils.createGetTask("/the/path", "myservice", params);
|
||||
Task task2 = cloudTasksUtils.createGetTask("/other/path", "yourservice", params);
|
||||
Task task1 = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, params);
|
||||
Task task2 = cloudTasksUtils.createGetTask("/other/path", Service.TOOLS, params);
|
||||
cloudTasksUtils.enqueue("test-queue", task1, task2);
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task1);
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task2);
|
||||
@@ -333,8 +342,8 @@ public class CloudTasksUtilsTest {
|
||||
|
||||
@Test
|
||||
void testSuccess_enqueueTasks_iterable() {
|
||||
Task task1 = cloudTasksUtils.createGetTask("/the/path", "myservice", params);
|
||||
Task task2 = cloudTasksUtils.createGetTask("/other/path", "yourservice", params);
|
||||
Task task1 = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, params);
|
||||
Task task2 = cloudTasksUtils.createGetTask("/other/path", Service.TOOLS, params);
|
||||
cloudTasksUtils.enqueue("test-queue", ImmutableList.of(task1, task2));
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task1);
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task2);
|
||||
@@ -20,6 +20,7 @@ import dagger.Provides;
|
||||
import dagger.Subcomponent;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.batch.AsyncTaskEnqueuerTest;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
|
||||
import google.registry.dns.DnsQueue;
|
||||
@@ -36,7 +37,6 @@ import google.registry.testing.FakeSleeper;
|
||||
import google.registry.tmch.TmchCertificateAuthority;
|
||||
import google.registry.tmch.TmchXmlSignature;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.Sleeper;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
||||
@@ -155,6 +155,8 @@ import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
@@ -182,6 +184,7 @@ import google.registry.persistence.VKey;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import google.registry.tmch.SmdrlCsvParser;
|
||||
import google.registry.tmch.TmchData;
|
||||
import google.registry.tmch.TmchTestData;
|
||||
@@ -192,9 +195,12 @@ import javax.annotation.Nullable;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.junitpioneer.jupiter.cartesian.CartesianTest;
|
||||
import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
|
||||
|
||||
@@ -224,6 +230,11 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
clock.setTo(DateTime.parse("1999-04-03T22:00:00.0Z").minus(Duration.millis(1)));
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
DatabaseMigrationStateSchedule.useUncachedForTest();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void initCreateTest() throws Exception {
|
||||
createTld("tld");
|
||||
@@ -390,7 +401,10 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.that(reloadResourceByForeignKey())
|
||||
.hasSmdId(null)
|
||||
.and()
|
||||
.hasLaunchNotice(null);
|
||||
.hasLaunchNotice(null)
|
||||
.and()
|
||||
.hasLordnPhase(LordnPhase.NONE);
|
||||
assertNoTasksEnqueued(QUEUE_CLAIMS, QUEUE_SUNRISE);
|
||||
assertNoTasksEnqueued(QUEUE_CLAIMS, QUEUE_SUNRISE);
|
||||
}
|
||||
|
||||
@@ -400,14 +414,20 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.hasSmdId(SMD_ID)
|
||||
.and()
|
||||
.hasLaunchNotice(null);
|
||||
String expectedPayload =
|
||||
String.format(
|
||||
"%s,%s,%s,1,%s",
|
||||
reloadResourceByForeignKey().getRepoId(),
|
||||
domainName,
|
||||
SMD_ID,
|
||||
SMD_VALID_TIME.plusMillis(17));
|
||||
assertTasksEnqueued(QUEUE_SUNRISE, new TaskMatcher().payload(expectedPayload));
|
||||
if (DatabaseMigrationStateSchedule.getValueAtTime(clock.nowUtc())
|
||||
.equals(MigrationState.NORDN_SQL)) {
|
||||
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.SUNRISE);
|
||||
} else {
|
||||
String expectedPayload =
|
||||
String.format(
|
||||
"%s,%s,%s,1,%s",
|
||||
reloadResourceByForeignKey().getRepoId(),
|
||||
domainName,
|
||||
SMD_ID,
|
||||
SMD_VALID_TIME.plusMillis(17));
|
||||
assertTasksEnqueued(QUEUE_SUNRISE, new TaskMatcher().payload(expectedPayload));
|
||||
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertClaimsLordn() throws Exception {
|
||||
@@ -421,13 +441,19 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"tmch",
|
||||
DateTime.parse("2010-08-16T09:00:00.0Z"),
|
||||
DateTime.parse("2009-08-16T09:00:00.0Z")));
|
||||
TaskMatcher task =
|
||||
new TaskMatcher()
|
||||
.payload(
|
||||
reloadResourceByForeignKey().getRepoId()
|
||||
+ ",example-one.tld,370d0b7c9223372036854775807,1,"
|
||||
+ "2009-08-16T09:00:00.017Z,2009-08-16T09:00:00.000Z");
|
||||
assertTasksEnqueued(QUEUE_CLAIMS, task);
|
||||
if (DatabaseMigrationStateSchedule.getValueAtTime(clock.nowUtc())
|
||||
.equals(MigrationState.NORDN_SQL)) {
|
||||
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.CLAIMS);
|
||||
} else {
|
||||
TaskMatcher task =
|
||||
new TaskMatcher()
|
||||
.payload(
|
||||
reloadResourceByForeignKey().getRepoId()
|
||||
+ ",example-one.tld,370d0b7c9223372036854775807,1,"
|
||||
+ "2009-08-16T09:00:00.017Z,2009-08-16T09:00:00.000Z");
|
||||
assertTasksEnqueued(QUEUE_CLAIMS, task);
|
||||
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(
|
||||
@@ -677,7 +703,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD"));
|
||||
persistContactsAndHosts();
|
||||
doSuccessfulTest(
|
||||
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6"));
|
||||
"tld",
|
||||
"domain_create_response_fee.xml",
|
||||
ImmutableMap.of("FEE_VERSION", "0.6", "FEE", "26.00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -685,7 +713,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
|
||||
persistContactsAndHosts();
|
||||
doSuccessfulTest(
|
||||
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11"));
|
||||
"tld",
|
||||
"domain_create_response_fee.xml",
|
||||
ImmutableMap.of("FEE_VERSION", "0.11", "FEE", "26.00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -693,7 +723,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
|
||||
persistContactsAndHosts();
|
||||
doSuccessfulTest(
|
||||
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12"));
|
||||
"tld",
|
||||
"domain_create_response_fee.xml",
|
||||
ImmutableMap.of("FEE_VERSION", "0.12", "FEE", "26.00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -701,7 +733,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.6"));
|
||||
persistContactsAndHosts();
|
||||
doSuccessfulTest(
|
||||
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6"));
|
||||
"tld",
|
||||
"domain_create_response_fee.xml",
|
||||
ImmutableMap.of("FEE_VERSION", "0.6", "FEE", "26.00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -709,7 +743,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.11"));
|
||||
persistContactsAndHosts();
|
||||
doSuccessfulTest(
|
||||
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11"));
|
||||
"tld",
|
||||
"domain_create_response_fee.xml",
|
||||
ImmutableMap.of("FEE_VERSION", "0.11", "FEE", "26.00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -717,7 +753,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.12"));
|
||||
persistContactsAndHosts();
|
||||
doSuccessfulTest(
|
||||
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12"));
|
||||
"tld",
|
||||
"domain_create_response_fee.xml",
|
||||
ImmutableMap.of("FEE_VERSION", "0.12", "FEE", "26.00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -939,8 +977,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_claimsNotice() throws Exception {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_claimsNotice(boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
clock.setTo(DateTime.parse("2009-08-16T09:00:00.0Z"));
|
||||
setEppInput("domain_create_claim_notice.xml");
|
||||
persistContactsAndHosts();
|
||||
@@ -950,8 +992,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertClaimsLordn();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_claimsNoticeInQuietPeriod() throws Exception {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_claimsNoticeInQuietPeriod(boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -1077,6 +1123,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_wrongFeeAmountTooHigh_defaultToken_v06() throws Exception {
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.setCreateBillingCost(Money.of(USD, 8))
|
||||
.build());
|
||||
// Expects fee of $26
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD"));
|
||||
persistContactsAndHosts();
|
||||
// $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year
|
||||
runFlowAssertResponse(
|
||||
loadFile(
|
||||
"domain_create_response_fee.xml",
|
||||
ImmutableMap.of("FEE_VERSION", "0.6", "FEE", "12.00")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_wrongFeeAmountTooLow_defaultToken_v06() throws Exception {
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.setCreateBillingCost(Money.of(USD, 100))
|
||||
.build());
|
||||
// Expects fee of $26
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD"));
|
||||
persistContactsAndHosts();
|
||||
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_wrongFeeAmount_v11() {
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
|
||||
@@ -1087,6 +1184,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_wrongFeeAmountTooHigh_defaultToken_v11() throws Exception {
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.setCreateBillingCost(Money.of(USD, 8))
|
||||
.build());
|
||||
// Expects fee of $26
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
|
||||
persistContactsAndHosts();
|
||||
// $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year
|
||||
runFlowAssertResponse(
|
||||
loadFile(
|
||||
"domain_create_response_fee.xml",
|
||||
ImmutableMap.of("FEE_VERSION", "0.11", "FEE", "12.00")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_wrongFeeAmountTooLow_defaultToken_v11() throws Exception {
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.setCreateBillingCost(Money.of(USD, 100))
|
||||
.build());
|
||||
// Expects fee of $26
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
|
||||
persistContactsAndHosts();
|
||||
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_wrongFeeAmount_v12() {
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
|
||||
@@ -1097,6 +1245,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_wrongFeeAmountTooHigh_defaultToken_v12() throws Exception {
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.setCreateBillingCost(Money.of(USD, 8))
|
||||
.build());
|
||||
// Expects fee of $26
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
|
||||
persistContactsAndHosts();
|
||||
// $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year
|
||||
runFlowAssertResponse(
|
||||
loadFile(
|
||||
"domain_create_response_fee.xml",
|
||||
ImmutableMap.of("FEE_VERSION", "0.12", "FEE", "12.00")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_wrongFeeAmountTooLow_defaultToken_v12() throws Exception {
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.setCreateBillingCost(Money.of(USD, 100))
|
||||
.build());
|
||||
// Expects fee of $26
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
|
||||
persistContactsAndHosts();
|
||||
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_wrongCurrency_v06() {
|
||||
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "EUR"));
|
||||
@@ -1220,8 +1419,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAllocationTokenWasRedeemed("abcDEF23456");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_anchorTenant_withClaims() throws Exception {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_anchorTenant_withClaims(boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setDomainName("example-one.tld")
|
||||
@@ -1289,8 +1492,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(SUNRISE, ANCHOR_TENANT));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_anchorTenantInSunrise_withSignedMark() throws Exception {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_anchorTenantInSunrise_withSignedMark(boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -1890,9 +2097,13 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(RESERVED));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_reservedNameCollisionDomain_inSunrise_setsServerHoldAndPollMessage()
|
||||
throws Exception {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_reservedNameCollisionDomain_inSunrise_setsServerHoldAndPollMessage(
|
||||
boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -2435,8 +2646,13 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"tld", "domain_create_response.xml", SUPERUSER, ImmutableMap.of("DOMAIN", "example.tld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark() throws Exception {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark(boolean usePullQueue)
|
||||
throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
clock.setTo(SMD_VALID_TIME);
|
||||
setEppInput(
|
||||
@@ -2458,8 +2674,13 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
}
|
||||
|
||||
/** Test that missing type= argument on launch create works in start-date sunrise. */
|
||||
@Test
|
||||
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark_noType() throws Exception {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark_noType(boolean usePullQueue)
|
||||
throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
clock.setTo(SMD_VALID_TIME);
|
||||
setEppInput(
|
||||
@@ -3512,4 +3733,97 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.isEqualTo(
|
||||
"The package token abc123 cannot be used to register names for longer than 1 year.");
|
||||
}
|
||||
|
||||
private static void useNordnSql() {
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(7), MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(7), MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
|
||||
.put(START_OF_TIME.plusMillis(8), MigrationState.NORDN_SQL)
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,11 +72,7 @@ public class UserTest extends EntityTestCase {
|
||||
assertThat(assertThrows(IllegalArgumentException.class, () -> builder.setUserRoles(null)))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("User roles cannot be null");
|
||||
|
||||
assertThat(assertThrows(IllegalArgumentException.class, builder::build))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Gaia ID cannot be null");
|
||||
builder.setGaiaId("gaiaId");
|
||||
|
||||
assertThat(assertThrows(IllegalArgumentException.class, builder::build))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Email address cannot be null");
|
||||
|
||||
@@ -221,7 +221,6 @@ public class DomainTest {
|
||||
"TheRegistrar",
|
||||
oneTimeBillKey))
|
||||
.setAutorenewEndTime(Optional.of(fakeClock.nowUtc().plusYears(2)))
|
||||
.setDnsRefreshRequestTime(Optional.of(fakeClock.nowUtc()))
|
||||
.build()));
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@ import google.registry.model.reporting.DomainTransactionRecord;
|
||||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.util.SerializeUtils;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -97,7 +95,6 @@ public class DomainHistoryTest extends EntityTestCase {
|
||||
.asBuilder()
|
||||
.setNameservers(host.createVKey())
|
||||
.setDsData(ImmutableSet.of(DomainDsData.create(1, 2, 3, new byte[] {0, 1, 2})))
|
||||
.setDnsRefreshRequestTime(Optional.of(DateTime.parse("2020-03-09T16:40:00Z")))
|
||||
.build();
|
||||
insertInDb(domain);
|
||||
return domain;
|
||||
|
||||
@@ -18,17 +18,14 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.model.server.Lock.LockState.FREE;
|
||||
import static google.registry.model.server.Lock.LockState.IN_USE;
|
||||
import static google.registry.model.server.Lock.LockState.OWNER_DIED;
|
||||
import static google.registry.model.server.Lock.LockState.TIMED_OUT;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.model.server.Lock.LockState;
|
||||
import google.registry.util.RequestStatusChecker;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@@ -41,7 +38,6 @@ public class LockTest extends EntityTestCase {
|
||||
private static final String RESOURCE_NAME = "foo";
|
||||
private static final Duration ONE_DAY = Duration.standardDays(1);
|
||||
private static final Duration TWO_MILLIS = Duration.millis(2);
|
||||
private static final RequestStatusChecker requestStatusChecker = mock(RequestStatusChecker.class);
|
||||
|
||||
private LockMetrics origLockMetrics;
|
||||
|
||||
@@ -52,7 +48,7 @@ public class LockTest extends EntityTestCase {
|
||||
private static Optional<Lock> acquire(
|
||||
String tld, Duration leaseLength, LockState expectedLockState) {
|
||||
Lock.lockMetrics = mock(LockMetrics.class);
|
||||
Optional<Lock> lock = Lock.acquire(RESOURCE_NAME, tld, leaseLength, requestStatusChecker, true);
|
||||
Optional<Lock> lock = Lock.acquire(RESOURCE_NAME, tld, leaseLength);
|
||||
verify(Lock.lockMetrics).recordAcquire(RESOURCE_NAME, tld, expectedLockState);
|
||||
verifyNoMoreInteractions(Lock.lockMetrics);
|
||||
Lock.lockMetrics = null;
|
||||
@@ -72,8 +68,6 @@ public class LockTest extends EntityTestCase {
|
||||
void beforeEach() {
|
||||
origLockMetrics = Lock.lockMetrics;
|
||||
Lock.lockMetrics = null;
|
||||
when(requestStatusChecker.getLogId()).thenReturn("current-request-id");
|
||||
when(requestStatusChecker.isRunning("current-request-id")).thenReturn(true);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -111,9 +105,6 @@ public class LockTest extends EntityTestCase {
|
||||
assertThat(acquire("", ONE_DAY, FREE)).isPresent();
|
||||
// We can't get it again while request is active
|
||||
assertThat(acquire("", ONE_DAY, IN_USE)).isEmpty();
|
||||
// But if request is finished, we can get it.
|
||||
when(requestStatusChecker.isRunning("current-request-id")).thenReturn(false);
|
||||
assertThat(acquire("", ONE_DAY, OWNER_DIED)).isPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -134,9 +125,7 @@ public class LockTest extends EntityTestCase {
|
||||
@Test
|
||||
void testFailure_emptyResourceName() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> Lock.acquire("", "", TWO_MILLIS, requestStatusChecker, true));
|
||||
assertThrows(IllegalArgumentException.class, () -> Lock.acquire("", "", TWO_MILLIS));
|
||||
assertThat(thrown).hasMessageThat().contains("resourceName cannot be null or empty");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,6 +23,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.cloud.tasks.v2.HttpMethod;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.beam.BeamActionTestBase;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
@@ -30,7 +31,6 @@ import google.registry.reporting.ReportingModule;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.IOException;
|
||||
import org.joda.time.Duration;
|
||||
import org.joda.time.YearMonth;
|
||||
|
||||
@@ -31,10 +31,10 @@ import com.google.api.services.dataflow.Dataflow.Projects.Locations.Jobs.Get;
|
||||
import com.google.api.services.dataflow.model.Job;
|
||||
import com.google.cloud.tasks.v2.HttpMethod;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.IOException;
|
||||
import org.joda.time.YearMonth;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
+1
-1
@@ -21,12 +21,12 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.cloud.tasks.v2.HttpMethod;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.beam.BeamActionTestBase;
|
||||
import google.registry.reporting.ReportingModule;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.IOException;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
// Copyright 2023 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.request.auth;
|
||||
|
||||
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature.Header;
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class ServiceAccountAuthenticationMechanismTest {
|
||||
|
||||
@Mock private TokenVerifier tokenVerifier;
|
||||
@Mock private HttpServletRequest request;
|
||||
|
||||
private JsonWebSignature token;
|
||||
private ServiceAccountAuthenticationMechanism serviceAccountAuthenticationMechanism;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
serviceAccountAuthenticationMechanism =
|
||||
new ServiceAccountAuthenticationMechanism(tokenVerifier, "sa-prefix@email.com");
|
||||
when(request.getHeader(AUTHORIZATION)).thenReturn("Bearer jwtValue");
|
||||
Payload payload = new Payload();
|
||||
payload.setEmail("sa-prefix@email.com");
|
||||
token = new JsonWebSignature(new Header(), payload, new byte[0], new byte[0]);
|
||||
when(tokenVerifier.verify("jwtValue")).thenReturn(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_authenticates() throws Exception {
|
||||
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isTrue();
|
||||
assertThat(authResult.authLevel()).isEqualTo(AuthLevel.APP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFails_authenticateWrongEmail() throws Exception {
|
||||
token.getPayload().set("email", "not-service-account-email@email.com");
|
||||
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFails_authenticateWrongHeader() throws Exception {
|
||||
when(request.getHeader(AUTHORIZATION)).thenReturn("BEARER asd");
|
||||
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import static org.mockito.Mockito.verify;
|
||||
import google.registry.model.server.Lock;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.UserServiceExtension;
|
||||
import google.registry.util.RequestStatusCheckerImpl;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@@ -134,7 +133,7 @@ final class LockHandlerImplTest {
|
||||
}
|
||||
|
||||
private LockHandler createTestLockHandler(@Nullable Lock acquiredLock) {
|
||||
return new LockHandlerImpl(new RequestStatusCheckerImpl(), clock) {
|
||||
return new LockHandlerImpl(clock) {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,8 +43,8 @@ import com.google.protobuf.Timestamp;
|
||||
import com.google.protobuf.util.Timestamps;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
|
||||
@@ -312,6 +312,7 @@ public final class DatabaseHelper {
|
||||
return persistResource(domain.asBuilder().setDeletionTime(deletionTime).build());
|
||||
}
|
||||
|
||||
// TODO: delete after pull queue migration.
|
||||
/** Persists a domain and enqueues a LORDN task of the appropriate type for it. */
|
||||
public static Domain persistDomainAndEnqueueLordn(final Domain domain) {
|
||||
final Domain persistedDomain = persistResource(domain);
|
||||
|
||||
@@ -27,6 +27,7 @@ import google.registry.model.domain.launch.LaunchNotice;
|
||||
import google.registry.model.domain.secdns.DomainDsData;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.testing.TruthChainer.And;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import java.util.Set;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -41,7 +42,7 @@ public final class DomainSubject extends AbstractEppResourceSubject<Domain, Doma
|
||||
}
|
||||
|
||||
public And<DomainSubject> hasDomainName(String domainName) {
|
||||
return hasValue(domainName, actual.getDomainName(), "has domainName");
|
||||
return hasValue(domainName, actual.getDomainName(), "domainName");
|
||||
}
|
||||
|
||||
public And<DomainSubject> hasExactlyDsData(DomainDsData... dsData) {
|
||||
@@ -49,15 +50,19 @@ public final class DomainSubject extends AbstractEppResourceSubject<Domain, Doma
|
||||
}
|
||||
|
||||
public And<DomainSubject> hasExactlyDsData(Set<DomainDsData> dsData) {
|
||||
return hasValue(dsData, actual.getDsData(), "has dsData");
|
||||
return hasValue(dsData, actual.getDsData(), "dsData");
|
||||
}
|
||||
|
||||
public And<DomainSubject> hasNumDsData(int num) {
|
||||
return hasValue(num, actual.getDsData().size(), "has num dsData");
|
||||
return hasValue(num, actual.getDsData().size(), "dsData.size()");
|
||||
}
|
||||
|
||||
public And<DomainSubject> hasLaunchNotice(LaunchNotice launchNotice) {
|
||||
return hasValue(launchNotice, actual.getLaunchNotice(), "has launchNotice");
|
||||
return hasValue(launchNotice, actual.getLaunchNotice(), "launchNotice");
|
||||
}
|
||||
|
||||
public And<DomainSubject> hasLordnPhase(LordnPhase lordnPhase) {
|
||||
return hasValue(lordnPhase, actual.getLordnPhase(), "lordnPhase");
|
||||
}
|
||||
|
||||
public And<DomainSubject> hasAuthInfoPwd(String pw) {
|
||||
@@ -67,7 +72,7 @@ public final class DomainSubject extends AbstractEppResourceSubject<Domain, Doma
|
||||
|
||||
public And<DomainSubject> hasCurrentSponsorRegistrarId(String registrarId) {
|
||||
return hasValue(
|
||||
registrarId, actual.getCurrentSponsorRegistrarId(), "has currentSponsorRegistrarId");
|
||||
registrarId, actual.getCurrentSponsorRegistrarId(), "currentSponsorRegistrarId");
|
||||
}
|
||||
|
||||
public And<DomainSubject> hasRegistrationExpirationTime(DateTime expiration) {
|
||||
|
||||
@@ -14,13 +14,17 @@
|
||||
|
||||
package google.registry.tmch;
|
||||
|
||||
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||
import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
|
||||
import static com.google.common.net.HttpHeaders.LOCATION;
|
||||
import static com.google.common.net.MediaType.FORM_DATA;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ForeignKeyUtils.load;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.loadByKey;
|
||||
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatabaseHelper.newDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistDomainAndEnqueueLordn;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
@@ -34,6 +38,7 @@ import static org.mockito.ArgumentMatchers.startsWith;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.api.taskqueue.LeaseOptions;
|
||||
@@ -45,19 +50,21 @@ import com.google.appengine.api.taskqueue.TransientFailureException;
|
||||
import com.google.apphosting.api.DeadlineExceededException;
|
||||
import com.google.common.base.VerifyException;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.launch.LaunchNotice;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.RequestParameters;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.testing.FakeUrlConnectionService;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.UrlConnectionException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -67,25 +74,32 @@ import java.net.URL;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
/** Unit tests for {@link NordnUploadAction}. */
|
||||
class NordnUploadActionTest {
|
||||
|
||||
private static final String CLAIMS_CSV =
|
||||
"1,2010-05-01T10:11:12.000Z,1\n"
|
||||
"1,2010-05-04T10:11:12.000Z,2\n"
|
||||
+ "roid,domain-name,notice-id,registrar-id,registration-datetime,ack-datetime,"
|
||||
+ "application-datetime\n"
|
||||
+ "2-TLD,claims-landrush1.tld,landrush1tcn,99999,2010-05-01T10:11:12.000Z,"
|
||||
+ "1969-12-31T23:00:00.000Z\n";
|
||||
+ "6-TLD,claims-landrush2.tld,landrush2tcn,88888,2010-05-03T10:11:12.000Z,"
|
||||
+ "2010-05-03T08:11:12.000Z\n"
|
||||
+ "8-TLD,claims-landrush1.tld,landrush1tcn,99999,2010-05-04T10:11:12.000Z,"
|
||||
+ "2010-05-04T09:11:12.000Z\n";
|
||||
|
||||
private static final String SUNRISE_CSV =
|
||||
"1,2010-05-01T10:11:12.000Z,1\n"
|
||||
"1,2010-05-04T10:11:12.000Z,2\n"
|
||||
+ "roid,domain-name,SMD-id,registrar-id,registration-datetime,application-datetime\n"
|
||||
+ "2-TLD,sunrise1.tld,my-smdid,99999,2010-05-01T10:11:12.000Z\n";
|
||||
+ "2-TLD,sunrise2.tld,new-smdid,88888,2010-05-01T10:11:12.000Z\n"
|
||||
+ "4-TLD,sunrise1.tld,my-smdid,99999,2010-05-02T10:11:12.000Z\n";
|
||||
|
||||
private static final String LOCATION_URL = "http://trololol";
|
||||
|
||||
@@ -116,8 +130,12 @@ class NordnUploadActionTest {
|
||||
when(httpUrlConnection.getHeaderField(LOCATION)).thenReturn("http://trololol");
|
||||
when(httpUrlConnection.getOutputStream()).thenReturn(connectionOutputStream);
|
||||
persistResource(loadRegistrar("TheRegistrar").asBuilder().setIanaIdentifier(99999L).build());
|
||||
persistResource(loadRegistrar("NewRegistrar").asBuilder().setIanaIdentifier(88888L).build());
|
||||
createTld("tld");
|
||||
persistResource(Registry.get("tld").asBuilder().setLordnUsername("lolcat").build());
|
||||
persistSunriseModeDomain();
|
||||
clock.advanceBy(Duration.standardDays(1));
|
||||
persistClaimsModeDomain();
|
||||
action.clock = clock;
|
||||
action.cloudTasksUtils = cloudTasksUtils;
|
||||
action.urlConnectionService = urlConnectionService;
|
||||
@@ -127,6 +145,7 @@ class NordnUploadActionTest {
|
||||
action.tmchMarksdbUrl = "http://127.0.0.1";
|
||||
action.random = new SecureRandom();
|
||||
action.retrier = new Retrier(new FakeSleeper(clock), 3);
|
||||
action.usePullQueue = Optional.empty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -137,7 +156,7 @@ class NordnUploadActionTest {
|
||||
makeTaskHandle("task1", "example", "csvLine1", "lordn-sunrise"),
|
||||
makeTaskHandle("task3", "example", "ending", "lordn-sunrise"));
|
||||
assertThat(NordnUploadAction.convertTasksToCsv(tasks, clock.nowUtc(), "col1,col2"))
|
||||
.isEqualTo("1,2010-05-01T10:11:12.000Z,3\ncol1,col2\ncsvLine1\ncsvLine2\nending\n");
|
||||
.isEqualTo("1,2010-05-04T10:11:12.000Z,3\ncol1,col2\ncsvLine1\ncsvLine2\nending\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -149,13 +168,13 @@ class NordnUploadActionTest {
|
||||
makeTaskHandle("task3", "example", "ending", "lordn-sunrise"),
|
||||
makeTaskHandle("task1", "example", "csvLine1", "lordn-sunrise"));
|
||||
assertThat(NordnUploadAction.convertTasksToCsv(tasks, clock.nowUtc(), "col1,col2"))
|
||||
.isEqualTo("1,2010-05-01T10:11:12.000Z,3\ncol1,col2\ncsvLine1\ncsvLine2\nending\n");
|
||||
.isEqualTo("1,2010-05-04T10:11:12.000Z,3\ncol1,col2\ncsvLine1\ncsvLine2\nending\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_convertTasksToCsv_doesntFailOnEmptyTasks() {
|
||||
assertThat(NordnUploadAction.convertTasksToCsv(ImmutableList.of(), clock.nowUtc(), "col1,col2"))
|
||||
.isEqualTo("1,2010-05-01T10:11:12.000Z,0\ncol1,col2\n");
|
||||
.isEqualTo("1,2010-05-04T10:11:12.000Z,0\ncol1,col2\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -187,122 +206,105 @@ class NordnUploadActionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_claimsMode_appendsTldAndClaimsToRequestUrl() throws Exception {
|
||||
persistClaimsModeDomain();
|
||||
action.run();
|
||||
assertThat(httpUrlConnection.getURL()).isEqualTo(new URL("http://127.0.0.1/LORDN/tld/claims"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_sunriseMode_appendsTldAndClaimsToRequestUrl() throws Exception {
|
||||
persistSunriseModeDomain();
|
||||
action.run();
|
||||
assertThat(httpUrlConnection.getURL()).isEqualTo(new URL("http://127.0.0.1/LORDN/tld/sunrise"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_usesMultipartContentType() throws Exception {
|
||||
persistClaimsModeDomain();
|
||||
action.run();
|
||||
verify(httpUrlConnection)
|
||||
.setRequestProperty(eq(CONTENT_TYPE), startsWith("multipart/form-data; boundary="));
|
||||
verify(httpUrlConnection).setRequestMethod("POST");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_hasPassword_setsAuthorizationHeader() {
|
||||
persistClaimsModeDomain();
|
||||
action.run();
|
||||
verify(httpUrlConnection)
|
||||
.setRequestProperty(
|
||||
AUTHORIZATION, "Basic bG9sY2F0OmF0dGFjaw=="); // echo -n lolcat:attack | base64
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_noPassword_doesntSendAuthorizationHeader() {
|
||||
void testSuccess_noPassword_doesntSendAuthorizationHeader() {
|
||||
action.lordnRequestInitializer = new LordnRequestInitializer(Optional.empty());
|
||||
persistClaimsModeDomain();
|
||||
action.run();
|
||||
verify(httpUrlConnection, times(0)).setRequestProperty(eq(AUTHORIZATION), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_claimsMode_payloadMatchesClaimsCsv() {
|
||||
persistClaimsModeDomain();
|
||||
void testSuccess_nothingScheduled() {
|
||||
persistResource(
|
||||
loadByKey(load(Domain.class, "claims-landrush1.tld", clock.nowUtc()))
|
||||
.asBuilder()
|
||||
.setLordnPhase(LordnPhase.NONE)
|
||||
.build());
|
||||
persistResource(
|
||||
loadByKey(load(Domain.class, "claims-landrush2.tld", clock.nowUtc()))
|
||||
.asBuilder()
|
||||
.setLordnPhase(LordnPhase.NONE)
|
||||
.build());
|
||||
action.run();
|
||||
assertThat(connectionOutputStream.toString(UTF_8)).contains(CLAIMS_CSV);
|
||||
verifyNoInteractions(httpUrlConnection);
|
||||
cloudTasksHelper.assertNoTasksEnqueued(NordnVerifyAction.QUEUE);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_claimsMode(boolean usePullQueue) throws Exception {
|
||||
testRun("claims", "claims-landrush1.tld", "claims-landrush2.tld", CLAIMS_CSV, usePullQueue);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_sunriseMode(boolean usePullQueue) throws Exception {
|
||||
testRun("sunrise", "sunrise1.tld", "sunrise2.tld", SUNRISE_CSV, usePullQueue);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_claimsMode_verifyTaskGetsEnqueuedWithClaimsCsv() {
|
||||
persistClaimsModeDomain();
|
||||
action.run();
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
NordnVerifyAction.QUEUE,
|
||||
new TaskMatcher()
|
||||
.url(NordnVerifyAction.PATH)
|
||||
.param(NordnVerifyAction.NORDN_URL_PARAM, LOCATION_URL)
|
||||
.header(CONTENT_TYPE, FORM_DATA.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_sunriseMode_payloadMatchesSunriseCsv() {
|
||||
persistSunriseModeDomain();
|
||||
action.run();
|
||||
assertThat(connectionOutputStream.toString(UTF_8)).contains(SUNRISE_CSV);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_noResponseContent_stillWorksNormally() throws Exception {
|
||||
void testSuccess_noResponseContent_stillWorksNormally() throws Exception {
|
||||
// Returning null only affects logging.
|
||||
when(httpUrlConnection.getInputStream()).thenReturn(new ByteArrayInputStream(new byte[] {}));
|
||||
persistSunriseModeDomain();
|
||||
action.run();
|
||||
assertThat(connectionOutputStream.toString(UTF_8)).contains(SUNRISE_CSV);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_sunriseMode_verifyTaskGetsEnqueuedWithSunriseCsv() {
|
||||
persistSunriseModeDomain();
|
||||
action.run();
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
NordnVerifyAction.QUEUE,
|
||||
new TaskMatcher()
|
||||
.url(NordnVerifyAction.PATH)
|
||||
.param(NordnVerifyAction.NORDN_URL_PARAM, LOCATION_URL)
|
||||
.header(CONTENT_TYPE, FORM_DATA.toString()));
|
||||
testRun("claims", "claims-landrush1.tld", "claims-landrush2.tld", CLAIMS_CSV, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_nullRegistryUser() {
|
||||
persistClaimsModeDomain();
|
||||
persistResource(Registry.get("tld").asBuilder().setLordnUsername(null).build());
|
||||
VerifyException thrown = assertThrows(VerifyException.class, action::run);
|
||||
assertThat(thrown).hasMessageThat().contains("lordnUsername is not set for tld.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchFailure() throws Exception {
|
||||
persistClaimsModeDomain();
|
||||
void testFailure_errorResponseCode() throws Exception {
|
||||
when(httpUrlConnection.getResponseCode()).thenReturn(SC_INTERNAL_SERVER_ERROR);
|
||||
assertThrows(UrlConnectionException.class, action::run);
|
||||
}
|
||||
|
||||
private static void persistClaimsModeDomain() {
|
||||
Domain domain = DatabaseHelper.newDomain("claims-landrush1.tld");
|
||||
@Test
|
||||
void testFailure_noLocationHeaderInResponse() throws Exception {
|
||||
when(httpUrlConnection.getHeaderField(LOCATION)).thenReturn(null);
|
||||
assertThrows(UrlConnectionException.class, action::run);
|
||||
}
|
||||
|
||||
private void persistClaimsModeDomain() {
|
||||
persistDomainAndEnqueueLordn(
|
||||
domain
|
||||
newDomain("claims-landrush2.tld")
|
||||
.asBuilder()
|
||||
.setCreationTimeForTest(clock.nowUtc())
|
||||
.setCreationRegistrarId("NewRegistrar")
|
||||
.setLaunchNotice(
|
||||
LaunchNotice.create(
|
||||
"landrush1tcn", null, null, domain.getCreationTime().minusHours(1)))
|
||||
LaunchNotice.create("landrush2tcn", null, null, clock.nowUtc().minusHours(2)))
|
||||
.setLordnPhase(LordnPhase.CLAIMS)
|
||||
.build());
|
||||
clock.advanceBy(Duration.standardDays(1));
|
||||
persistDomainAndEnqueueLordn(
|
||||
newDomain("claims-landrush1.tld")
|
||||
.asBuilder()
|
||||
.setCreationTimeForTest(clock.nowUtc())
|
||||
.setLaunchNotice(
|
||||
LaunchNotice.create("landrush1tcn", null, null, clock.nowUtc().minusHours(1)))
|
||||
.setLordnPhase(LordnPhase.CLAIMS)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void persistSunriseModeDomain() {
|
||||
action.phase = "sunrise";
|
||||
Domain domain = DatabaseHelper.newDomain("sunrise1.tld");
|
||||
persistDomainAndEnqueueLordn(domain.asBuilder().setSmdId("my-smdid").build());
|
||||
persistDomainAndEnqueueLordn(
|
||||
newDomain("sunrise2.tld")
|
||||
.asBuilder()
|
||||
.setCreationTimeForTest(clock.nowUtc())
|
||||
.setCreationRegistrarId("NewRegistrar")
|
||||
.setSmdId("new-smdid")
|
||||
.setLordnPhase(LordnPhase.SUNRISE)
|
||||
.build());
|
||||
clock.advanceBy(Duration.standardDays(1));
|
||||
persistDomainAndEnqueueLordn(
|
||||
newDomain("sunrise1.tld")
|
||||
.asBuilder()
|
||||
.setCreationTimeForTest(clock.nowUtc())
|
||||
.setSmdId("my-smdid")
|
||||
.setLordnPhase(LordnPhase.SUNRISE)
|
||||
.build());
|
||||
}
|
||||
|
||||
private static TaskHandle makeTaskHandle(
|
||||
@@ -311,4 +313,46 @@ class NordnUploadActionTest {
|
||||
TaskOptions.Builder.withPayload(payload).method(Method.PULL).tag(tag).taskName(taskName),
|
||||
queue);
|
||||
}
|
||||
|
||||
private void verifyColumnCleared(String domainName) {
|
||||
VKey<Domain> domainKey = load(Domain.class, domainName, clock.nowUtc());
|
||||
Domain domain = loadByKey(domainKey);
|
||||
assertThat(domain.getLordnPhase()).isEqualTo(LordnPhase.NONE);
|
||||
}
|
||||
|
||||
private void testRun(
|
||||
String phase, String domain1, String domain2, String csv, boolean usePullQueue)
|
||||
throws Exception {
|
||||
action.usePullQueue = Optional.of(usePullQueue);
|
||||
action.phase = phase;
|
||||
action.run();
|
||||
verify(httpUrlConnection)
|
||||
.setRequestProperty(
|
||||
AUTHORIZATION, "Basic bG9sY2F0OmF0dGFjaw=="); // echo -n lolcat:attack | base64
|
||||
verify(httpUrlConnection)
|
||||
.setRequestProperty(eq(CONTENT_TYPE), startsWith("multipart/form-data; boundary="));
|
||||
verify(httpUrlConnection).setRequestMethod("POST");
|
||||
assertThat(httpUrlConnection.getURL())
|
||||
.isEqualTo(new URL("http://127.0.0.1/LORDN/tld/" + phase));
|
||||
assertThat(connectionOutputStream.toString(UTF_8)).contains(csv);
|
||||
if (!usePullQueue) {
|
||||
verifyColumnCleared(domain1);
|
||||
verifyColumnCleared(domain2);
|
||||
} else {
|
||||
assertThat(
|
||||
getQueue("lordn-" + phase)
|
||||
.leaseTasks(
|
||||
LeaseOptions.Builder.withTag("tld")
|
||||
.leasePeriod(1, TimeUnit.HOURS)
|
||||
.countLimit(100)))
|
||||
.isEmpty();
|
||||
}
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
NordnVerifyAction.QUEUE,
|
||||
new TaskMatcher()
|
||||
.url(NordnVerifyAction.PATH)
|
||||
.param(NordnVerifyAction.NORDN_URL_PARAM, LOCATION_URL)
|
||||
.param(RequestParameters.PARAM_TLD, "tld")
|
||||
.header(CONTENT_TYPE, FORM_DATA.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright 2023 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;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Tests for {@link CreateUserCommand}. */
|
||||
public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
|
||||
@Test
|
||||
void testSuccess() throws Exception {
|
||||
runCommandForced("--email", "user@example.test");
|
||||
User onlyUser = Iterables.getOnlyElement(DatabaseHelper.loadAllOf(User.class));
|
||||
assertThat(onlyUser.getEmailAddress()).isEqualTo("user@example.test");
|
||||
assertThat(onlyUser.getUserRoles().isAdmin()).isFalse();
|
||||
assertThat(onlyUser.getUserRoles().getGlobalRole()).isEqualTo(GlobalRole.NONE);
|
||||
assertThat(onlyUser.getUserRoles().getRegistrarRoles()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_admin() throws Exception {
|
||||
runCommandForced("--email", "user@example.test", "--admin", "true");
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().isAdmin()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_globalRole() throws Exception {
|
||||
runCommandForced("--email", "user@example.test", "--global_role", "FTE");
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().getGlobalRole())
|
||||
.isEqualTo(GlobalRole.FTE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_registrarRoles() throws Exception {
|
||||
runCommandForced(
|
||||
"--email",
|
||||
"user@example.test",
|
||||
"--registrar_roles",
|
||||
"TheRegistrar=ACCOUNT_MANAGER,NewRegistrar=PRIMARY_CONTACT");
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().getRegistrarRoles())
|
||||
.isEqualTo(
|
||||
ImmutableMap.of(
|
||||
"TheRegistrar",
|
||||
RegistrarRole.ACCOUNT_MANAGER,
|
||||
"NewRegistrar",
|
||||
RegistrarRole.PRIMARY_CONTACT));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_alreadyExists() throws Exception {
|
||||
runCommandForced("--email", "user@example.test");
|
||||
assertThat(
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> runCommandForced("--email", "user@example.test")))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("A user with email user@example.test already exists");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2023 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;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Tests for {@link DeleteUserCommand}. */
|
||||
public class DeleteUserCommandTest extends CommandTestCase<DeleteUserCommand> {
|
||||
|
||||
@Test
|
||||
void testSuccess_deletesUser() throws Exception {
|
||||
User user =
|
||||
new User.Builder()
|
||||
.setEmailAddress("email@example.test")
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).setIsAdmin(true).build())
|
||||
.build();
|
||||
UserDao.saveUser(user);
|
||||
assertThat(UserDao.loadUser("email@example.test")).isPresent();
|
||||
runCommandForced("--email", "email@example.test");
|
||||
assertThat(UserDao.loadUser("email@example.test")).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_nonexistent() {
|
||||
assertThat(
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> runCommandForced("--email", "nonexistent@example.test")))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Email does not correspond to a valid user");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright 2023 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;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Tests for {@link UpdateUserCommand}. */
|
||||
public class UpdateUserCommandTest extends CommandTestCase<UpdateUserCommand> {
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
UserDao.saveUser(
|
||||
new User.Builder()
|
||||
.setEmailAddress("user@example.test")
|
||||
.setUserRoles(new UserRoles.Builder().build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_admin() throws Exception {
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().isAdmin()).isFalse();
|
||||
runCommandForced("--email", "user@example.test", "--admin", "true");
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().isAdmin()).isTrue();
|
||||
runCommandForced("--email", "user@example.test", "--admin", "false");
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().isAdmin()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_registrarRoles() throws Exception {
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().getRegistrarRoles())
|
||||
.isEmpty();
|
||||
runCommandForced(
|
||||
"--email",
|
||||
"user@example.test",
|
||||
"--registrar_roles",
|
||||
"TheRegistrar=ACCOUNT_MANAGER,NewRegistrar=PRIMARY_CONTACT");
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().getRegistrarRoles())
|
||||
.isEqualTo(
|
||||
ImmutableMap.of(
|
||||
"TheRegistrar",
|
||||
RegistrarRole.ACCOUNT_MANAGER,
|
||||
"NewRegistrar",
|
||||
RegistrarRole.PRIMARY_CONTACT));
|
||||
runCommandForced("--email", "user@example.test", "--registrar_roles", "");
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().getRegistrarRoles())
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_globalRole() throws Exception {
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().getGlobalRole())
|
||||
.isEqualTo(GlobalRole.NONE);
|
||||
runCommandForced("--email", "user@example.test", "--global_role", "FTE");
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().getGlobalRole())
|
||||
.isEqualTo(GlobalRole.FTE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_doesntExist() {
|
||||
assertThat(
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> runCommandForced("--email", "nonexistent@example.test")))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("User nonexistent@example.test not found");
|
||||
}
|
||||
}
|
||||
@@ -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.util;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.testing.LogsSubject.assertAboutLogs;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.api.log.LogQuery;
|
||||
import com.google.appengine.api.log.LogService;
|
||||
import com.google.appengine.api.log.RequestLogs;
|
||||
import com.google.apphosting.api.ApiProxy;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.testing.TestLogHandler;
|
||||
import google.registry.testing.UserServiceExtension;
|
||||
import java.util.logging.Level;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link RequestStatusCheckerImpl}. */
|
||||
final class RequestStatusCheckerImplTest {
|
||||
|
||||
private static final TestLogHandler logHandler = new TestLogHandler();
|
||||
|
||||
private static final RequestStatusChecker requestStatusChecker = new RequestStatusCheckerImpl();
|
||||
|
||||
/**
|
||||
* Matcher for the expected LogQuery in {@link RequestStatusCheckerImpl#isRunning}.
|
||||
*
|
||||
* Because LogQuery doesn't have a .equals function, we have to create an actual matcher to make
|
||||
* sure we have the right argument in our mocks.
|
||||
*/
|
||||
private static LogQuery expectedLogQuery(final String requestLogId) {
|
||||
return argThat(
|
||||
object -> {
|
||||
assertThat(object).isInstanceOf(LogQuery.class);
|
||||
assertThat(object.getRequestIds()).containsExactly(requestLogId);
|
||||
assertThat(object.getIncludeAppLogs()).isFalse();
|
||||
assertThat(object.getIncludeIncomplete()).isTrue();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// We do not actually need to set up user service, rather, we just need this extension to set up
|
||||
// App Engine environment so the status checker can make an App Engine API call.
|
||||
@RegisterExtension UserServiceExtension userService = new UserServiceExtension("");
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
JdkLoggerConfig.getConfig(RequestStatusCheckerImpl.class).addHandler(logHandler);
|
||||
RequestStatusCheckerImpl.logService = mock(LogService.class);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
JdkLoggerConfig.getConfig(RequestStatusCheckerImpl.class).removeHandler(logHandler);
|
||||
}
|
||||
|
||||
// If a logId is unrecognized, it could be that the log hasn't been uploaded yet - so we assume
|
||||
// it's a request that has just started running recently.
|
||||
@Test
|
||||
void testIsRunning_unrecognized() {
|
||||
when(RequestStatusCheckerImpl.logService.fetch(expectedLogQuery("12345678")))
|
||||
.thenReturn(ImmutableList.of());
|
||||
assertThat(requestStatusChecker.isRunning("12345678")).isTrue();
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(Level.INFO, "Queried an unrecognized requestLogId");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsRunning_notFinished() {
|
||||
RequestLogs requestLogs = new RequestLogs();
|
||||
requestLogs.setFinished(false);
|
||||
|
||||
when(RequestStatusCheckerImpl.logService.fetch(expectedLogQuery("12345678")))
|
||||
.thenReturn(ImmutableList.of(requestLogs));
|
||||
|
||||
assertThat(requestStatusChecker.isRunning("12345678")).isTrue();
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(Level.INFO, "isFinished: false");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsRunning_finished() {
|
||||
RequestLogs requestLogs = new RequestLogs();
|
||||
requestLogs.setFinished(true);
|
||||
|
||||
when(RequestStatusCheckerImpl.logService.fetch(expectedLogQuery("12345678")))
|
||||
.thenReturn(ImmutableList.of(requestLogs));
|
||||
|
||||
assertThat(requestStatusChecker.isRunning("12345678")).isFalse();
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(Level.INFO, "isFinished: true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLogId_returnsRequestLogId() {
|
||||
String expectedLogId = ApiProxy.getCurrentEnvironment().getAttributes().get(
|
||||
"com.google.appengine.runtime.request_log_id").toString();
|
||||
assertThat(requestStatusChecker.getLogId()).isEqualTo(expectedLogId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLogId_createsLog() {
|
||||
requestStatusChecker.getLogId();
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(Level.INFO, "Current requestLogId: ");
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
<extension>
|
||||
<fee:creData xmlns:fee="urn:ietf:params:xml:ns:fee-%FEE_VERSION%">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:fee description="create">26.00</fee:fee>
|
||||
<fee:fee description="create">%FEE%</fee:fee>
|
||||
</fee:creData>
|
||||
</extension>
|
||||
<trID>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -133,3 +133,8 @@ V132__drop_gae_user_id_from_registrar_poc.sql
|
||||
V133__add_pull_queue_replace_columns.sql
|
||||
V134__drop_not_null_request_id_lock_table.sql
|
||||
V135__null_gaia_id_user.sql
|
||||
V136__add_dns_refresh_request_table.sql
|
||||
V137__add_process_time_column.sql
|
||||
V138__drop_dns_refresh_request_time_column.sql
|
||||
V139__add_allowed_epp_actions_column.sql
|
||||
V140__rename_process_time_column_in_dns_refresh_request_table.sql
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Copyright 2023 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.
|
||||
|
||||
create table "DnsRefreshRequest"
|
||||
(
|
||||
id bigserial not null,
|
||||
name text not null,
|
||||
request_time timestamptz not null,
|
||||
tld text not null,
|
||||
type text not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create index IDX8gtvnbk64yskcvrdp61f5ied3 on "DnsRefreshRequest" (request_time);
|
||||
@@ -0,0 +1,18 @@
|
||||
-- Copyright 2023 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.
|
||||
|
||||
ALTER TABLE "DnsRefreshRequest"
|
||||
ADD COLUMN IF NOT EXISTS process_time timestamptz NOT NULL;
|
||||
|
||||
CREATE INDEX IDX3i7i2ktts9d7lcjbs34h0pvwo ON "DnsRefreshRequest" (process_time);
|
||||
@@ -0,0 +1,19 @@
|
||||
-- Copyright 2023 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.
|
||||
|
||||
ALTER TABLE "Domain" DROP COLUMN IF EXISTS dns_refresh_request_time;
|
||||
ALTER TABLE "DomainHistory" DROP COLUMN IF EXISTS dns_refresh_request_time;
|
||||
|
||||
ALTER TABLE "Host" DROP COLUMN IF EXISTS dns_refresh_request_time;
|
||||
ALTER TABLE "HostHistory" DROP COLUMN IF EXISTS dns_refresh_request_time;
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Copyright 2023 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.
|
||||
|
||||
ALTER TABLE "AllocationToken" ADD COLUMN allowed_epp_actions text[];
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
-- Copyright 2023 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.
|
||||
|
||||
ALTER TABLE "DnsRefreshRequest" RENAME COLUMN process_time TO last_process_time;
|
||||
CREATE INDEX IDXfdk2xpil2x1gh0omt84k2y3o1 ON "DnsRefreshRequest" (last_process_time);
|
||||
DROP INDEX IDX3i7i2ktts9d7lcjbs34h0pvwo;
|
||||
|
||||
|
||||
|
||||
@@ -276,7 +276,6 @@
|
||||
deletion_poll_message_id int8,
|
||||
domain_name text,
|
||||
idn_table_name text,
|
||||
dns_refresh_request_time timestamptz,
|
||||
last_transfer_time timestamptz,
|
||||
launch_notice_accepted_time timestamptz,
|
||||
launch_notice_expiration_time timestamptz,
|
||||
@@ -349,7 +348,6 @@
|
||||
deletion_poll_message_id int8,
|
||||
domain_name text,
|
||||
idn_table_name text,
|
||||
dns_refresh_request_time timestamptz,
|
||||
last_transfer_time timestamptz,
|
||||
launch_notice_accepted_time timestamptz,
|
||||
launch_notice_expiration_time timestamptz,
|
||||
@@ -451,7 +449,6 @@
|
||||
statuses text[],
|
||||
host_name text,
|
||||
inet_addresses text[],
|
||||
dns_refresh_request_time timestamptz,
|
||||
last_superordinate_change timestamptz,
|
||||
last_transfer_time timestamptz,
|
||||
superordinate_domain text,
|
||||
@@ -472,7 +469,6 @@
|
||||
history_xml_bytes bytea,
|
||||
host_name text,
|
||||
inet_addresses text[],
|
||||
dns_refresh_request_time timestamptz,
|
||||
last_superordinate_change timestamptz,
|
||||
last_transfer_time timestamptz,
|
||||
superordinate_domain text,
|
||||
@@ -492,7 +488,6 @@
|
||||
scope text not null,
|
||||
acquired_time timestamptz not null,
|
||||
expiration_time timestamptz not null,
|
||||
request_log_id text,
|
||||
primary key (resource_name, scope)
|
||||
);
|
||||
|
||||
@@ -751,7 +746,7 @@
|
||||
id bigserial not null,
|
||||
update_timestamp timestamptz,
|
||||
email_address text not null,
|
||||
gaia_id text not null,
|
||||
gaia_id text,
|
||||
registry_lock_password_hash text,
|
||||
registry_lock_password_salt text,
|
||||
global_role text not null,
|
||||
@@ -801,7 +796,6 @@ create index IDXc5aw4pk1vkd6ymhvkpanmoadv on "Domain" (domain_name);
|
||||
create index IDXr22ciyccwi9rrqmt1ro0s59qf on "Domain" (tech_contact);
|
||||
create index IDXrwl38wwkli1j7gkvtywi9jokq on "Domain" (tld);
|
||||
create index IDXa7fu0bqynfb79rr80528b4jqt on "Domain" (registrant_contact);
|
||||
create index IDXcws5mvmpl8o10wrhde780ors2 on "Domain" (dns_refresh_request_time);
|
||||
create index IDXnjhib7v6fj7dhj5qydkefkl2u on "Domain" (lordn_phase);
|
||||
create index IDXsfci08jgsymxy6ovh4k7r358c on "Domain" (billing_recurrence_id);
|
||||
create index IDX3y3k7m2bkgahm9sixiohgyrga on "Domain" (transfer_billing_event_id);
|
||||
@@ -825,7 +819,6 @@ create index IDXkpkh68n6dy5v51047yr6b0e9l on "Host" (host_name);
|
||||
create index IDXy98mebut8ix1v07fjxxdkqcx on "Host" (creation_time);
|
||||
create index IDXovmntef6l45tw2bsfl56tcugx on "Host" (deletion_time);
|
||||
create index IDXl49vydnq0h5j1piefwjy4i8er on "Host" (current_sponsor_registrar_id);
|
||||
create index IDX7wg0yn3wdux3xsc4pfaljqf08 on "Host" (dns_refresh_request_time);
|
||||
create index IDXfg2nnjlujxo6cb9fha971bq2n on "HostHistory" (creation_time);
|
||||
create index IDX1iy7njgb7wjmj9piml4l2g0qi on "HostHistory" (history_registrar_id);
|
||||
create index IDXkkwbwcwvrdkkqothkiye4jiff on "HostHistory" (host_name);
|
||||
|
||||
@@ -53,7 +53,8 @@ CREATE TABLE public."AllocationToken" (
|
||||
token_type text,
|
||||
redemption_domain_history_id bigint,
|
||||
renewal_price_behavior text DEFAULT 'DEFAULT'::text NOT NULL,
|
||||
registration_behavior text DEFAULT 'DEFAULT'::text NOT NULL
|
||||
registration_behavior text DEFAULT 'DEFAULT'::text NOT NULL,
|
||||
allowed_epp_actions text[]
|
||||
);
|
||||
|
||||
|
||||
@@ -340,6 +341,39 @@ CREATE TABLE public."DelegationSignerData" (
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: DnsRefreshRequest; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public."DnsRefreshRequest" (
|
||||
id bigint NOT NULL,
|
||||
name text NOT NULL,
|
||||
request_time timestamp with time zone NOT NULL,
|
||||
tld text NOT NULL,
|
||||
type text NOT NULL,
|
||||
last_process_time timestamp with time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: DnsRefreshRequest_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public."DnsRefreshRequest_id_seq"
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: DnsRefreshRequest_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public."DnsRefreshRequest_id_seq" OWNED BY public."DnsRefreshRequest".id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: Domain; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
@@ -395,7 +429,6 @@ CREATE TABLE public."Domain" (
|
||||
transfer_history_entry_id bigint,
|
||||
transfer_repo_id text,
|
||||
transfer_poll_message_id_3 bigint,
|
||||
dns_refresh_request_time timestamp with time zone,
|
||||
current_package_token text,
|
||||
lordn_phase text DEFAULT 'NONE'::text NOT NULL
|
||||
);
|
||||
@@ -485,7 +518,6 @@ CREATE TABLE public."DomainHistory" (
|
||||
transfer_history_entry_id bigint,
|
||||
transfer_repo_id text,
|
||||
transfer_poll_message_id_3 bigint,
|
||||
dns_refresh_request_time timestamp with time zone,
|
||||
current_package_token text,
|
||||
lordn_phase text DEFAULT 'NONE'::text NOT NULL
|
||||
);
|
||||
@@ -597,8 +629,7 @@ CREATE TABLE public."Host" (
|
||||
superordinate_domain text,
|
||||
inet_addresses text[],
|
||||
update_timestamp timestamp with time zone,
|
||||
transfer_poll_message_id_3 bigint,
|
||||
dns_refresh_request_time timestamp with time zone
|
||||
transfer_poll_message_id_3 bigint
|
||||
);
|
||||
|
||||
|
||||
@@ -631,8 +662,7 @@ CREATE TABLE public."HostHistory" (
|
||||
statuses text[],
|
||||
host_repo_id text NOT NULL,
|
||||
update_timestamp timestamp with time zone,
|
||||
transfer_poll_message_id_3 bigint,
|
||||
dns_refresh_request_time timestamp with time zone
|
||||
transfer_poll_message_id_3 bigint
|
||||
);
|
||||
|
||||
|
||||
@@ -1133,6 +1163,13 @@ CREATE SEQUENCE public.project_wide_unique_id_seq
|
||||
ALTER TABLE ONLY public."ClaimsList" ALTER COLUMN revision_id SET DEFAULT nextval('public."ClaimsList_revision_id_seq"'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: DnsRefreshRequest id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public."DnsRefreshRequest" ALTER COLUMN id SET DEFAULT nextval('public."DnsRefreshRequest_id_seq"'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: DomainTransactionRecord id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
@@ -1277,6 +1314,14 @@ ALTER TABLE ONLY public."DelegationSignerData"
|
||||
ADD CONSTRAINT "DelegationSignerData_pkey" PRIMARY KEY (domain_repo_id, key_tag, algorithm, digest_type, digest);
|
||||
|
||||
|
||||
--
|
||||
-- Name: DnsRefreshRequest DnsRefreshRequest_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public."DnsRefreshRequest"
|
||||
ADD CONSTRAINT "DnsRefreshRequest_pkey" PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: DomainDsDataHistory DomainDsDataHistory_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@@ -1531,13 +1576,6 @@ CREATE INDEX allocation_token_domain_name_idx ON public."AllocationToken" USING
|
||||
CREATE UNIQUE INDEX database_migration_state_schedule_singleton ON public."DatabaseMigrationStateSchedule" USING btree ((true));
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_dns_refresh_request_time_idx; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX domain_dns_refresh_request_time_idx ON public."Domain" USING btree (dns_refresh_request_time);
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_history_to_ds_data_history_idx; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
@@ -1665,10 +1703,10 @@ CREATE INDEX idx73l103vc5900ig3p4odf0cngt ON public."BillingEvent" USING btree (
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx7wg0yn3wdux3xsc4pfaljqf08; Type: INDEX; Schema: public; Owner: -
|
||||
-- Name: idx8gtvnbk64yskcvrdp61f5ied3; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx7wg0yn3wdux3xsc4pfaljqf08 ON public."Host" USING btree (dns_refresh_request_time) WHERE (dns_refresh_request_time IS NOT NULL);
|
||||
CREATE INDEX idx8gtvnbk64yskcvrdp61f5ied3 ON public."DnsRefreshRequest" USING btree (request_time);
|
||||
|
||||
|
||||
--
|
||||
@@ -1776,6 +1814,13 @@ CREATE INDEX idxe7wu46c7wpvfmfnj4565abibp ON public."PollMessage" USING btree (r
|
||||
CREATE INDEX idxeokttmxtpq2hohcioe5t2242b ON public."BillingCancellation" USING btree (registrar_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idxfdk2xpil2x1gh0omt84k2y3o1; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idxfdk2xpil2x1gh0omt84k2y3o1 ON public."DnsRefreshRequest" USING btree (last_process_time);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idxfg2nnjlujxo6cb9fha971bq2n; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user