1
0
mirror of https://github.com/google/nomulus synced 2026-07-09 09:37:04 +00:00

Compare commits

...

36 Commits

Author SHA1 Message Date
gbrodman fd822dd333 Add create/delete/update commands for User objects (#1936)
This also includes the change of allowing the Java User object to have a
null GAIA ID (when creating user objects, we don't know what the GAIA ID
is).
2023-03-07 17:18:48 -05:00
Ben McIlwain 9b93749d43 Double the number of frontend instances from 12 to 24 (#1954)
It seems like we're hitting App Engine capacity issues resulting in actual pages
now (for whatever reason, but likely one customer), and we obviously don't want
that.
2023-03-06 16:04:28 -05:00
Pavlo Tkach 71a8579ece Move App Engine cron jobs to cloud scheduler (#1939) 2023-03-01 13:40:56 -05:00
Lai Jiang cda51f13dc Remove dnsRefreshRequestTime from EppResources (#1943)
We have decided to use a separate table (#1940) to track DNS refresh requests
due to performance reasons.

See: go/registry-pull-queue-redesign
2023-03-01 13:40:30 -05:00
Lai Jiang 1de5b5dcc1 Add a process time column to DnsRefreshRequest (#1948)
The value of the column would be set to START_OF_TIME for new entries.
Every time a row is read, the value is updated to the current time. This
allows concurrent reads to not repeatedly read the same entry that has the
earliest request time, because they would only look for rows that have a value
of process time that is before current time - some padding time.

This basically fulfills the same function that LEASE_PADDING gives us
when using a pull queue, whereas a task would be leased for a certain
time, during which time they would not be leased by anyone else.

See: https://cs.opensource.google/nomulus/nomulus/+/master:core/src/main/java/google/registry/dns/ReadDnsQueueAction.java;l=99?q=readdnsqueue&ss=nomulus%2Fnomulus
2023-02-28 16:52:02 -05:00
sarahcaseybot 32279e42e4 Allow incorrect fee extensions on domain creates with default tokens (#1927)
* Modify fee extension to accept larger costs on creates with default tokens

* Add tests

* Add some comments to tests
2023-02-28 14:24:03 -05:00
Lai Jiang ba0f90bdaf Add support for Nordn upload without using pull queues. (#1925)
This PR adds an alternative method to upload Lordn to Nordn server without
using App Engine pull queue. A new database migration stage is added to control
whether a new task is scheduled with the old or new method. The
NordnUploadAction is configured to process both kind of tasks. Once the tasks
scheduled for the old tasks are all processed, we can start using the
new method exclusively.

See: go/registry-pull-queue-redesign
2023-02-28 12:57:27 -05:00
Lai Jiang 85308eb975 Ignore invalid old CRL when performing update. (#1946)
There is no point comparing the old CRL to the new ones when the old one
is invalid. This could happen when the CA cert rotates, after which the
old CRL stop being valid as it fails signature verification against the
new cert.

This change will allow us to keep updating the CRL after a CA rotation without
having to manually delete the old CRL from the database.

See b/270983553.

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1946)
<!-- Reviewable:end -->
2023-02-28 10:00:18 -05:00
Lai Jiang ed62f27a4a Update kythe vnames mapping (#1944) 2023-02-27 17:09:57 -05:00
Ben McIlwain 75851399ba Remove "letter G with stroke" from Extended Latin IDN table (#1938)
ICANN doesn't like this character because it's confusable with a normal G (the
stroke tends to get lost in the visual clutter of the descender), and .com's
Extended Latin table doesn't use it either. Best to get rid of it.
2023-02-23 16:27:15 -05:00
Lai Jiang 6d54c8d113 Add allowed license for json (#1942)
For some reason `./gradlew clean build` on master is failing for me on
multiple machines due to a new org.json:json version triggering license
violations, even though the lock files are not changing.

Note that the old versions are still present because if I remove
"The JSON license", which the old versions use, the check also fails...
2023-02-23 11:37:31 -05:00
Lai Jiang 34dfa2760e Add a table to record EPP resources needing DNS refresh (#1940) 2023-02-22 14:18:28 -05:00
Lai Jiang ff39a4a763 Change default beam job region (#1937)
For reasons that I cannot explain, the same expand recurring billing
event pipeline would fail in us-east1 but succeed in us-central1.

See:

https://pantheon.corp.google.com/dataflow/jobs/us-central1/2023-02-09_14_52_24-162498476138221714;graphView=0?project=domain-registry

https://pantheon.corp.google.com/dataflow/jobs/us-east1/2023-02-09_14_26_07-4564782062878841960;graphView=1?project=domain-registry

Also improved how the accuracy of the metrics:

It is observed that both counters are consistently higher for the same
start and end times when running in dry run mode. There is no way to
test for consistency when not running in dry run, for obviously reasons.

I can make the recurrings in scope counter consistent by not updating it
in a side-effect-causing transaction, but there is no way around the
other counter. It can only be trusted when running in dry run mode,
unfortunately.
2023-02-13 15:57:32 -05:00
gbrodman b1cd8c5a6f Add a frontend endpoint for retrieving a domain in JSON form (#1916)
We might (likely will) modify some of the fiddly bits around this (maybe
the GSON serialization, where we do the actual authorization, etc) but
this should be a decent basic shell structure for endpoints that the new
registrar console can call to retrieve JSON results.
2023-02-09 15:09:42 -05:00
gbrodman 28c7bc3085 Generate and use an IAP-enabled ID token in the proxy (#1926)
This is only generated and used if "iapClientId" is set in the proxy
config. If so, we use code similar to
https://cloud.google.com/iap/docs/authentication-howto#obtaining_an_oidc_token_for_the_default_service_account
to generate an ID token that is valid for IAP. We set the token on the
Proxy-Authorization header so that we can keep using the pre-existing
access token as well -- IAP allows for us to use either the
Authorization header or the Proxy-Authorization header.
2023-02-09 14:50:35 -05:00
gbrodman f36d22f4b1 Allow null GAIA IDs for User objects (#1933)
We were under the mistaken impression before that there was a reliable
way to, out-of-band, get a GAIA ID for a particular email address.
Unfortunately, that isn't the case (at least, not in a scalable way or
one that support agents could use). As a result, we have to allow null
GAIA IDs in the database.

When we (or the support team) create new users, we will only specify the
email address and not the GAIA ID. Then, when the user logs in for the
first time, we will have the GAIA ID from the provided ID token, and we
can populate it then.
2023-02-08 16:10:34 -05:00
Lai Jiang ef3ce79b8a Install procps in schema-deployer image (#1934)
It turns out this one uses pgrep and pkill as well, go figure...

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1934)
<!-- Reviewable:end -->
2023-02-08 09:59:47 -05:00
Lai Jiang 85317e3982 Update TMCH root certificate (#1918)
See b/260945047.

Also refactored the corresponding tests, which should future updates easier.

This change should be deployed at or around 2023-02-15T16:00:00Z.
2023-02-06 22:39:54 -05:00
Lai Jiang a53b71ecd5 Install procps (#1932)
The schema verifier script needs pgrep and pkill, which do not come with
Debian.
2023-02-06 19:45:04 -05:00
Lai Jiang fc9446876f Install curl (#1931)
Tested by running "docker build .".
2023-02-06 16:45:52 -05:00
dependabot[bot] 654b165dff Bump http-cache-semantics from 4.1.0 to 4.1.1 in /console-webapp (#1929)
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-06 13:22:50 -05:00
Lai Jiang 14d68d4cb2 Change base image for schema-verifier and schema-deployer (#1930)
Ubuntu 18.04 is entering EOL and the Cloud Build jobs are failing,
seemingly due to connection error to 18.04 repos:

https://pantheon.corp.google.com/cloud-build/builds;region=global/126a7c90-4322-41f1-ba1c-a10e38a32dab;step=5?project=domain-registry-dev

We use Debian 10 for the main builder, so it's better to keep everything
on the same schedule:

https://cs.opensource.google/nomulus/nomulus/+/master:release/builder/Dockerfile

Debian 10 is supported till June 2024:

https://wiki.debian.org/LTS
2023-02-06 13:09:37 -05:00
Lai Jiang bbf405d566 Fix expand recurring billing event pipeline (#1928) 2023-02-06 11:33:57 -05:00
sarahcaseybot 356f7d0099 Modify DomainCreateFlow to check for an applicable defaultPromoToken (#1904)
* Modify DomainCreateFlow to check for an applicable defaultPromoToken

* Add handling for deleted tokens

* Change cache to allocation token cache

* Abstract away cache methods

* Use AllocationToken.getAll in create flow

* Filter out empty tokens
2023-02-01 14:53:51 -05:00
dependabot[bot] 70509cfe46 Bump ua-parser-js from 0.7.31 to 0.7.33 in /console-webapp (#1924)
Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.31 to 0.7.33.
- [Release notes](https://github.com/faisalman/ua-parser-js/releases)
- [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/changelog.md)
- [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.31...0.7.33)

---
updated-dependencies:
- dependency-name: ua-parser-js
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Lai Jiang <jianglai@google.com>
2023-01-31 14:52:26 -05:00
sarahcaseybot 5e081f4692 Prevent ending package tokens with active domains (#1919)
* Prevent ending package tokens with active domains

* Fix bad formatting in comments

* Fix lots of nits
2023-01-30 16:13:23 -05:00
Lai Jiang 07b87bbb4d Remove @IdAllocation annotation from repoId (#1923)
This annotation only works for Long or long field.
2023-01-30 15:40:40 -05:00
gbrodman 6fabbb62d2 Use the Proxy-Authorization header when using nomulus + IAP (#1921) 2023-01-26 15:16:32 -05:00
Lai Jiang d8a882daa0 Add fields needed to implement pull queue alternative (#1915) 2023-01-25 15:26:00 -05:00
Pavlo Tkach de8c6fd316 Add a condition update precaution to validateNewState (#1920) 2023-01-25 14:53:12 -05:00
Weimin Yu ae68917bdd Upgrade to Gradle 7.3.2 (#1922)
This is an 'easy' upgrade that requires a minor change in
common/build.gradle and the removal of an unnecessary import in buildSrc.

Gradle 7.4 and above has breaking changes that break the latest nebula lint plugin. We may have to wait a while.
2023-01-25 12:47:35 -05:00
Lai Jiang 0736137a22 Update ExpandRecurringBillingEventsAction to use the beam pipeline (#1907)
Due to the way the beam pipeline is designed, it will expand an
recurring billing event when its event time is in scope for expansion,
instead of billing time. This means that the one time will be generated
45 days earlier. This would negate the need to check if the expansion is
finished when generating monthly invoices.

We will need to backfill the past 45 days of onetimes before the new
code is deployed. As an illustration, with the old code, a cursor time
of 2023-01-17 means that all auto-renewals whose billing time is before
2023-01-17 were created, which corresponds to an effective cursor time
of 2022-12-03 (45 days before 2023-01-17) for event time. This cursor
will need to be brought to 2023-01-17 to ensure that there is no gap in
generated event times when switching to use the new code.
2023-01-23 19:08:04 -05:00
Pavlo Tkach c4b7929506 Remove not null constraint request_log_id column (#1917) 2023-01-23 09:37:20 -05:00
Lai Jiang e6974a98bc Add columns needed to implement pull queue alternative (#1914) 2023-01-20 14:17:06 -05:00
Lai Jiang 630ae1f802 Delete TaskQueueUtils (#1908)
For push queues, use CloudTasksUtils. Pull queues for now directly calls
the GAE task queue APIs. The usage of pull queues will be soon replaced.
2023-01-19 14:45:18 -05:00
Lai Jiang 925c9ba9e8 Remove datastore related code (#1906) 2023-01-19 14:44:11 -05:00
449 changed files with 18593 additions and 19713 deletions
+52 -54
View File
@@ -9,33 +9,32 @@ com.fasterxml.jackson:jackson-bom:2.14.1=compileClasspath,testCompileClasspath,t
com.github.ben-manes.caffeine:caffeine:2.7.0=annotationProcessor,testAnnotationProcessor
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,testAnnotationProcessor
com.google.android:annotations:4.1.1.4=testRuntimeClasspath
com.google.api-client:google-api-client:2.1.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:gapic-google-cloud-storage-v2:2.16.0-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-storage-v2:2.16.0-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-iam-v1:1.6.22=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-storage-v2:2.16.0-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-common-protos:2.11.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-iam-v1:1.6.22=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:api-common:2.2.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-grpc:2.20.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-httpjson:0.105.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax:2.20.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client:2.1.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:gapic-google-cloud-storage-v2:2.17.2-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-storage-v2:2.17.2-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-storage-v2:2.17.2-alpha=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-common-protos:2.13.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-iam-v1:1.8.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:api-common:2.5.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-grpc:2.22.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-httpjson:0.107.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax:2.22.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-storage:v1-rev20220705-2.0.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-credentials:1.13.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-oauth2-http:1.13.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-credentials:1.14.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-oauth2-http:1.14.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.value:auto-value-annotations:1.10.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.value:auto-value:1.10.1=annotationProcessor
com.google.auto.value:auto-value:1.10.1=annotationProcessor,compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto:auto-common:0.10=annotationProcessor,testAnnotationProcessor
com.google.cloud:google-cloud-core-grpc:2.9.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-http:2.9.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core:2.9.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-storage:2.16.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-grpc:2.9.4=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-http:2.9.4=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core:2.9.4=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-storage:2.17.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.code.findbugs:jFormatString:3.0.0=annotationProcessor,testAnnotationProcessor
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.10=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.10.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.common.html.types:types:1.0.6=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotation:2.3.4=annotationProcessor,testAnnotationProcessor
com.google.errorprone:error_prone_annotations:2.16=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.18.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.3.4=annotationProcessor,checkstyle,testAnnotationProcessor
com.google.errorprone:error_prone_check_api:2.3.4=annotationProcessor,testAnnotationProcessor
com.google.errorprone:error_prone_core:2.3.4=annotationProcessor,testAnnotationProcessor
@@ -57,8 +56,8 @@ com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,testAnnotationProce
com.google.j2objc:j2objc-annotations:1.3=checkstyle,compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.jsinterop:jsinterop-annotations:1.0.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.oauth-client:google-oauth-client:1.34.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java-util:3.21.10=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java:3.21.10=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java-util:3.21.12=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java:3.21.12=compileClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java:3.4.0=annotationProcessor,testAnnotationProcessor
com.google.re2j:re2j:1.6=testRuntimeClasspath
com.google.template:soy:2021-02-01=compileClasspath,testCompileClasspath,testRuntimeClasspath
@@ -72,19 +71,19 @@ commons-codec:commons-codec:1.15=compileClasspath,testCompileClasspath,testRunti
commons-collections:commons-collections:3.2.2=checkstyle
commons-logging:commons-logging:1.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
info.picocli:picocli:4.5.2=checkstyle
io.grpc:grpc-alts:1.51.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-api:1.51.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-auth:1.51.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-context:1.51.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-core:1.51.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-googleapis:1.51.0=testRuntimeClasspath
io.grpc:grpc-grpclb:1.51.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty-shaded:1.51.0=testRuntimeClasspath
io.grpc:grpc-protobuf-lite:1.51.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf:1.51.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-services:1.51.0=testRuntimeClasspath
io.grpc:grpc-stub:1.51.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-xds:1.51.0=testRuntimeClasspath
io.grpc:grpc-alts:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-api:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-auth:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-context:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-core:1.52.1=testRuntimeClasspath
io.grpc:grpc-googleapis:1.52.1=testRuntimeClasspath
io.grpc:grpc-grpclb:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty-shaded:1.52.1=testRuntimeClasspath
io.grpc:grpc-protobuf-lite:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-services:1.52.1=testRuntimeClasspath
io.grpc:grpc-stub:1.52.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-xds:1.52.1=testRuntimeClasspath
io.opencensus:opencensus-api:0.31.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-http-util:0.31.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-proto:0.2.0=testRuntimeClasspath
@@ -93,8 +92,8 @@ javax.annotation:javax.annotation-api:1.3.2=compileClasspath,testCompileClasspat
javax.annotation:jsr250-api:1.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
javax.inject:javax.inject:1=compileClasspath,testCompileClasspath,testRuntimeClasspath
junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.12.16=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.12.16=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.12.22=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.12.22=testCompileClasspath,testRuntimeClasspath
net.sf.saxon:Saxon-HE:10.3=checkstyle
org.antlr:antlr4-runtime:4.8-1=checkstyle
org.apache.commons:commons-lang3:3.12.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
@@ -104,41 +103,40 @@ org.apache.httpcomponents:httpcore:4.4.15=compileClasspath,testCompileClasspath,
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
org.checkerframework:checker-qual:2.11.1=checkstyle
org.checkerframework:checker-qual:3.0.0=annotationProcessor,testAnnotationProcessor
org.checkerframework:checker-qual:3.28.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.checkerframework:checker-qual:3.29.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.checkerframework:dataflow:3.0.0=annotationProcessor,testAnnotationProcessor
org.checkerframework:javacutil:3.0.0=annotationProcessor,testAnnotationProcessor
org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,testAnnotationProcessor
org.codehaus.mojo:animal-sniffer-annotations:1.22=testRuntimeClasspath
org.conscrypt:conscrypt-openjdk-uber:2.5.2=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath
org.jacoco:org.jacoco.agent:0.8.6=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.6=jacocoAnt
org.jacoco:org.jacoco.core:0.8.6=jacocoAnt
org.jacoco:org.jacoco.report:0.8.6=jacocoAnt
org.jacoco:org.jacoco.agent:0.8.7=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.7=jacocoAnt
org.jacoco:org.jacoco.core:0.8.7=jacocoAnt
org.jacoco:org.jacoco.report:0.8.7=jacocoAnt
org.javassist:javassist:3.26.0-GA=checkstyle
org.json:json:20160212=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit:junit-bom:5.9.1=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-core:4.9.0=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.9.2=testCompileClasspath,testRuntimeClasspath
org.junit:junit-bom:5.9.2=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-core:5.0.0=testCompileClasspath,testRuntimeClasspath
org.objenesis:objenesis:3.3=testRuntimeClasspath
org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-analysis:7.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-analysis:8.0.1=jacocoAnt
org.ow2.asm:asm-analysis:9.1=jacocoAnt
org.ow2.asm:asm-commons:7.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-commons:8.0.1=jacocoAnt
org.ow2.asm:asm-commons:9.1=jacocoAnt
org.ow2.asm:asm-tree:7.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-tree:8.0.1=jacocoAnt
org.ow2.asm:asm-tree:9.1=jacocoAnt
org.ow2.asm:asm-util:7.0=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm:7.0=compileClasspath
org.ow2.asm:asm:8.0.1=jacocoAnt
org.ow2.asm:asm:9.1=testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm:9.1=jacocoAnt,testCompileClasspath,testRuntimeClasspath
org.pcollections:pcollections:2.1.2=annotationProcessor,testAnnotationProcessor
org.plumelib:plume-util:1.0.6=annotationProcessor,testAnnotationProcessor
org.plumelib:reflection-util:0.0.2=annotationProcessor,testAnnotationProcessor
org.plumelib:require-javadoc:0.1.0=annotationProcessor,testAnnotationProcessor
org.reflections:reflections:0.9.12=checkstyle
org.threeten:threetenbp:1.6.4=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.threeten:threetenbp:1.6.5=compileClasspath,testCompileClasspath,testRuntimeClasspath
empty=
@@ -17,7 +17,6 @@ package google.registry.gradle.plugin;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import google.registry.gradle.plugin.ProjectData.TaskData;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
+1
View File
@@ -38,6 +38,7 @@ configurations {
// All testing util classes. Other projects may declare dependency as:
// testImplementation project(path: 'common', configuration: 'testing')
create("testing")
testing.extendsFrom testingCompileOnly
}
+13 -14
View File
@@ -45,22 +45,21 @@ org.checkerframework:dataflow:3.0.0=annotationProcessor,errorprone,testAnnotatio
org.checkerframework:javacutil:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
org.hamcrest:hamcrest-core:1.3=default,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
org.jacoco:org.jacoco.agent:0.8.6=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.6=jacocoAnt
org.jacoco:org.jacoco.core:0.8.6=jacocoAnt
org.jacoco:org.jacoco.report:0.8.6=jacocoAnt
org.jacoco:org.jacoco.agent:0.8.7=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.7=jacocoAnt
org.jacoco:org.jacoco.core:0.8.7=jacocoAnt
org.jacoco:org.jacoco.report:0.8.7=jacocoAnt
org.javassist:javassist:3.26.0-GA=checkstyle
org.junit.jupiter:junit-jupiter-api:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit:junit-bom:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.9.2=testCompileClasspath,testRuntimeClasspath
org.junit:junit-bom:5.9.2=testCompileClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-analysis:8.0.1=jacocoAnt
org.ow2.asm:asm-commons:8.0.1=jacocoAnt
org.ow2.asm:asm-tree:8.0.1=jacocoAnt
org.ow2.asm:asm:8.0.1=jacocoAnt
org.ow2.asm:asm:9.1=compileClasspath,default,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
org.ow2.asm:asm-analysis:9.1=jacocoAnt
org.ow2.asm:asm-commons:9.1=jacocoAnt
org.ow2.asm:asm-tree:9.1=jacocoAnt
org.ow2.asm:asm:9.1=compileClasspath,default,deploy_jar,jacocoAnt,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
org.pcollections:pcollections:2.1.2=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
org.plumelib:plume-util:1.0.6=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
org.plumelib:reflection-util:0.0.2=annotationProcessor,errorprone,testAnnotationProcessor,testingAnnotationProcessor
@@ -35,7 +35,7 @@ public abstract class DateTimeUtils {
*
* <p>This value is (2^63-1)/1000 rounded down. AppEngine stores dates as 64 bit microseconds, but
* Java uses milliseconds, so this is the largest representable date that will survive a
* round-trip through Datastore.
* round-trip through the database.
*/
public static final DateTime END_OF_TIME = new DateTime(Long.MAX_VALUE / 1000, DateTimeZone.UTC);
@@ -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,
+8 -8
View File
@@ -31,15 +31,15 @@ org.checkerframework:checker-qual:3.0.0=annotationProcessor,errorprone,testAnnot
org.checkerframework:dataflow:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor
org.checkerframework:javacutil:3.0.0=annotationProcessor,errorprone,testAnnotationProcessor
org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,errorprone,testAnnotationProcessor
org.jacoco:org.jacoco.agent:0.8.6=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.6=jacocoAnt
org.jacoco:org.jacoco.core:0.8.6=jacocoAnt
org.jacoco:org.jacoco.report:0.8.6=jacocoAnt
org.jacoco:org.jacoco.agent:0.8.7=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.7=jacocoAnt
org.jacoco:org.jacoco.core:0.8.7=jacocoAnt
org.jacoco:org.jacoco.report:0.8.7=jacocoAnt
org.javassist:javassist:3.26.0-GA=checkstyle
org.ow2.asm:asm-analysis:8.0.1=jacocoAnt
org.ow2.asm:asm-commons:8.0.1=jacocoAnt
org.ow2.asm:asm-tree:8.0.1=jacocoAnt
org.ow2.asm:asm:8.0.1=jacocoAnt
org.ow2.asm:asm-analysis:9.1=jacocoAnt
org.ow2.asm:asm-commons:9.1=jacocoAnt
org.ow2.asm:asm-tree:9.1=jacocoAnt
org.ow2.asm:asm:9.1=jacocoAnt
org.pcollections:pcollections:2.1.2=annotationProcessor,errorprone,testAnnotationProcessor
org.plumelib:plume-util:1.0.6=annotationProcessor,errorprone,testAnnotationProcessor
org.plumelib:reflection-util:0.0.2=annotationProcessor,errorprone,testAnnotationProcessor
+12 -12
View File
@@ -6824,9 +6824,9 @@
"dev": true
},
"node_modules/http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
"dev": true
},
"node_modules/http-deceiver": {
@@ -11362,9 +11362,9 @@
}
},
"node_modules/ua-parser-js": {
"version": "0.7.31",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==",
"version": "0.7.33",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
"integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==",
"dev": true,
"funding": [
{
@@ -17202,9 +17202,9 @@
"dev": true
},
"http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
"dev": true
},
"http-deceiver": {
@@ -20623,9 +20623,9 @@
"dev": true
},
"ua-parser-js": {
"version": "0.7.31",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==",
"version": "0.7.33",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
"integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==",
"dev": true
},
"unicode-canonical-property-names-ecmascript": {
-4
View File
@@ -68,8 +68,6 @@ def dockerIncompatibleTestPatterns = [
// Nomulus classes, e.g., threads and objects retained by frameworks.
// TODO(weiminyu): identify cause and fix offending tests.
def fragileTestPatterns = [
// Test Datastore inexplicably aborts transaction.
"google/registry/model/tmch/ClaimsListShardTest.*",
// Changes cache timeouts and for some reason appears to have contention
// with other tests.
"google/registry/whois/WhoisCommandFactoryTest.*",
@@ -168,7 +166,6 @@ dependencies {
implementation deps['com.beust:jcommander']
implementation deps['com.github.ben-manes.caffeine:caffeine']
implementation deps['com.google.api:gax']
implementation deps['com.google.api.grpc:proto-google-cloud-datastore-v1']
implementation deps['com.google.api.grpc:proto-google-common-protos']
implementation deps['com.google.api.grpc:proto-google-cloud-secretmanager-v1']
implementation deps['com.google.api-client:google-api-client']
@@ -192,7 +189,6 @@ dependencies {
implementation deps['com.google.auth:google-auth-library-credentials']
implementation deps['com.google.auth:google-auth-library-oauth2-http']
implementation deps['com.google.cloud.bigdataoss:util']
implementation deps['com.google.cloud.datastore:datastore-v1-proto-client']
implementation deps['com.google.cloud.sql:jdbc-socket-factory-core']
runtimeOnly deps['com.google.cloud.sql:postgres-socket-factory']
implementation deps['com.google.cloud:google-cloud-secretmanager']
+150 -151
View File
@@ -22,13 +22,13 @@ com.github.ben-manes.caffeine:caffeine:2.9.3=compileClasspath,default,deploy_jar
com.github.docker-java:docker-java-api:3.2.13=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport-zerodep:3.2.13=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport:3.2.13=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jffi:1.3.9=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jffi:1.3.10=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-a64asm:1.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-constants:0.10.3=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-enxio:0.32.13=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-ffi:2.2.11=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-posix:3.1.15=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-unixsocket:0.38.17=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-constants:0.10.4=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-enxio:0.32.14=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-ffi:2.2.13=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-posix:3.1.16=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-unixsocket:0.38.19=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-x86asm:1.0.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.android:annotations:4.1.1.4=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
@@ -37,48 +37,47 @@ com.google.api-client:google-api-client-jackson2:1.32.2=compileClasspath,default
com.google.api-client:google-api-client-java6:1.35.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-servlet:1.35.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client:1.35.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:gapic-google-cloud-storage-v2:2.16.0-alpha=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:2.23.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.147.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.147.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:gapic-google-cloud-storage-v2:2.17.2-alpha=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:2.25.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.149.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.149.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:1.27.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigtable-v2:2.14.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.102.20=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsublite-v1:1.7.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:6.31.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:6.31.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-v1:6.31.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-storage-v2:2.16.0-alpha=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-common-protos:2.9.6=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-iam-v1:1.6.22=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1:2.23.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta1:0.147.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta2:0.147.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-admin-v2:2.14.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-v2:2.14.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-datastore-v1:0.102.5=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-firestore-v1:3.6.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigtable-v2:2.16.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.103.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsublite-v1:1.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:6.33.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:6.33.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-v1:6.33.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-storage-v2:2.17.2-alpha=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-common-protos:2.10.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1:2.25.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta1:0.149.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta2:0.149.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-admin-v2:2.16.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-v2:2.16.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-datastore-v1:0.103.5=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-firestore-v1:3.7.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-monitoring-v3:1.64.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
com.google.api.grpc:proto-google-cloud-monitoring-v3:3.4.6=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsub-v1:1.102.20=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsublite-v1:1.7.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1:2.6.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:2.6.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:6.31.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:6.31.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-v1:6.31.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-storage-v2:2.16.0-alpha=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2:2.6.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta2:0.96.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta3:0.96.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-common-protos:2.11.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-iam-v1:1.6.22=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:api-common:2.2.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-grpc:2.20.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-httpjson:0.105.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax:2.20.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-monitoring-v3:3.6.0=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsub-v1:1.103.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsublite-v1:1.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1:2.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:2.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:6.33.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:6.33.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-v1:6.33.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-storage-v2:2.17.2-alpha=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2:2.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta2:0.99.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta3:0.99.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-common-protos:2.13.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-iam-v1:1.8.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:api-common:2.5.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-grpc:2.22.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-httpjson:0.107.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax:2.22.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-appengine:v1-rev20221205-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-appengine:v1-rev20230109-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-bigquery:v2-rev20220924-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-clouddebugger:v2-rev20220318-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20220828-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -88,22 +87,21 @@ com.google.apis:google-api-services-drive:v2-rev393-1.25.0=compileClasspath,defa
com.google.apis:google-api-services-groupssettings:v1-rev20210624-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-healthcare:v1-rev20220818-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-iamcredentials:v1-rev20210326-1.32.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-monitoring:v3-rev20221205-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-monitoring:v3-rev20230123-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-pubsub:v1-rev20220904-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sheets:v4-rev20220927-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sqladmin:v1beta4-rev20221017-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sheets:v4-rev20221216-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sqladmin:v1beta4-rev20230111-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-storage:v1-rev20220705-2.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-1.0-sdk:1.9.86=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
com.google.appengine:appengine-api-1.0-sdk:2.0.10=testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-stubs:2.0.10=testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-testing:1.9.86=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-credentials:1.13.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-oauth2-http:1.13.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-credentials:1.14.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-oauth2-http:1.14.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.service:auto-service-annotations:1.0.1=annotationProcessor,compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.service:auto-service:1.0.1=annotationProcessor
com.google.auto.value:auto-value-annotations:1.10.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.value:auto-value:1.10.1=annotationProcessor,testAnnotationProcessor
com.google.auto.value:auto-value:1.9=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.value:auto-value:1.10.1=annotationProcessor,compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.auto:auto-common:0.10=errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.auto:auto-common:1.2=annotationProcessor
com.google.closure-stylesheets:closure-stylesheets:1.5.0=css
@@ -112,30 +110,30 @@ com.google.cloud.bigdataoss:util:2.2.6=compileClasspath,default,deploy_jar,nonpr
com.google.cloud.bigtable:bigtable-client-core:1.26.3=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.bigtable:bigtable-metrics-api:1.26.3=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.datastore:datastore-v1-proto-client:2.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:jdbc-socket-factory-core:1.7.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:postgres-socket-factory:1.7.2=default,deploy_jar,runtimeClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigquerystorage:2.23.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable-stats:2.14.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable:2.14.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-grpc:2.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-http:2.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core:2.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-firestore:3.6.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:jdbc-socket-factory-core:1.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:postgres-socket-factory:1.9.0=default,deploy_jar,runtimeClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigquerystorage:2.25.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable-stats:2.16.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable:2.16.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-grpc:2.9.4=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-http:2.9.4=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core:2.9.4=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-firestore:3.7.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-monitoring:1.82.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
com.google.cloud:google-cloud-monitoring:3.4.6=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-nio:0.125.0=testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsub:1.120.20=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsublite:1.7.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-secretmanager:2.6.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-spanner:6.31.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-storage:2.16.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-tasks:2.6.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:grpc-gcp:1.2.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.6.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-monitoring:3.6.0=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-nio:0.126.3=testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsub:1.121.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsublite:1.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-secretmanager:2.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-spanner:6.33.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-storage:2.17.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-tasks:2.9.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:grpc-gcp:1.3.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.7.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.code.findbugs:jFormatString:3.0.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.code.findbugs:jsr305:3.0.1=css
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,default,deploy_jar,errorprone,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntime,nonprodRuntimeClasspath,runtime,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.10=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.10.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.7=css,soy
com.google.common.html.types:types:1.0.6=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
com.google.dagger:dagger-compiler:2.44.2=annotationProcessor,testAnnotationProcessor
@@ -144,7 +142,7 @@ com.google.dagger:dagger-spi:2.44.2=annotationProcessor,testAnnotationProcessor
com.google.dagger:dagger:2.44.2=annotationProcessor,compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.devtools.ksp:symbol-processing-api:1.7.0-1.0.6=annotationProcessor,testAnnotationProcessor
com.google.errorprone:error_prone_annotation:2.3.4=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.errorprone:error_prone_annotations:2.16=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.18.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.3.4=checkstyle,errorprone,nonprodAnnotationProcessor,soy
com.google.errorprone:error_prone_annotations:2.7.1=annotationProcessor,testAnnotationProcessor
com.google.errorprone:error_prone_check_api:2.3.4=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
@@ -191,9 +189,9 @@ com.google.oauth-client:google-oauth-client-java6:1.34.1=compileClasspath,defaul
com.google.oauth-client:google-oauth-client-jetty:1.34.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.oauth-client:google-oauth-client-servlet:1.34.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.oauth-client:google-oauth-client:1.34.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java-util:3.21.10=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java-util:3.21.12=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java:2.5.0=css
com.google.protobuf:protobuf-java:3.21.10=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java:3.21.12=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java:3.4.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.protobuf:protobuf-java:4.0.0-rc-2=soy
com.google.re2j:re2j:1.6=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -242,37 +240,37 @@ io.confluent:kafka-schema-registry-client:5.3.2=compileClasspath,default,deploy_
io.dropwizard.metrics:metrics-core:3.1.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.github.classgraph:classgraph:4.8.104=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.github.java-diff-utils:java-diff-utils:4.12=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-alts:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-api:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-auth:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-census:1.49.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-context:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-core:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-googleapis:1.51.0=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-grpclb:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty-shaded:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty:1.49.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf-lite:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-rls:1.49.2=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-services:1.49.2=compileClasspath,nonprodCompileClasspath,testCompileClasspath
io.grpc:grpc-services:1.51.0=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-stub:1.51.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-xds:1.49.2=compileClasspath,nonprodCompileClasspath,testCompileClasspath
io.grpc:grpc-xds:1.51.0=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.netty:netty-buffer:4.1.77.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-http2:4.1.77.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-http:4.1.77.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-socks:4.1.77.Final=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.netty:netty-codec:4.1.77.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-common:4.1.77.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-handler-proxy:4.1.77.Final=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.netty:netty-handler:4.1.77.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-resolver:4.1.77.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-alts:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-api:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-auth:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-census:1.50.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-context:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-core:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-googleapis:1.52.1=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-grpclb:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty-shaded:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty:1.50.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf-lite:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-rls:1.50.2=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-services:1.50.2=compileClasspath,nonprodCompileClasspath,testCompileClasspath
io.grpc:grpc-services:1.52.1=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-stub:1.52.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-xds:1.50.2=compileClasspath,nonprodCompileClasspath,testCompileClasspath
io.grpc:grpc-xds:1.52.1=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.netty:netty-buffer:4.1.79.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-http2:4.1.79.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-http:4.1.79.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-socks:4.1.79.Final=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.netty:netty-codec:4.1.79.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-common:4.1.79.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-handler-proxy:4.1.79.Final=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.netty:netty-handler:4.1.79.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-resolver:4.1.79.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-tcnative-boringssl-static:2.0.52.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-tcnative-classes:2.0.52.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-transport-native-unix-common:4.1.77.Final=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.netty:netty-transport:4.1.77.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-transport-native-unix-common:4.1.79.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-transport:4.1.79.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-api:0.31.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-exemplar-util:0.31.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-grpc-metrics:0.31.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -304,8 +302,9 @@ jline:jline:1.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonp
joda-time:joda-time:2.10.10=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
junit:junit:4.13.2=default,nonprodCompileClasspath,nonprodRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
net.arnx:nashorn-promise:0.1.1=nonprodRuntime,runtime,testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.12.16=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.12.18=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.12.22=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.12.18=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
net.bytebuddy:byte-buddy:1.12.22=testCompileClasspath,testRuntimeClasspath
net.java.dev.javacc:javacc:4.1=css
net.java.dev.jna:jna:5.8.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.ltgt.gradle.incap:incap:0.2=annotationProcessor,testAnnotationProcessor
@@ -315,22 +314,22 @@ org.apache.arrow:arrow-format:5.0.0=compileClasspath,default,deploy_jar,nonprodC
org.apache.arrow:arrow-memory-core:5.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.arrow:arrow-vector:5.0.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.avro:avro:1.8.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-fn-execution:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-job-management:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-pipeline:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-construction-java:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-java:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-direct-java:2.43.0=testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-java-fn-execution:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-core:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-expansion-service:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-arrow:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-protobuf:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-fn-execution:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-kafka:2.43.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-fn-execution:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-job-management:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-pipeline:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-construction-java:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-java:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-direct-java:2.44.0=testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-java-fn-execution:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-core:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-expansion-service:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-arrow:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-protobuf:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-fn-execution:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-kafka:2.44.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-vendor-grpc-1_48_1:0.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-vendor-guava-26_0-jre:0.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-compress:1.22=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -340,8 +339,8 @@ org.apache.commons:commons-lang3:3.12.0=compileClasspath,default,deploy_jar,nonp
org.apache.commons:commons-text:1.10.0=testCompileClasspath,testRuntimeClasspath
org.apache.ftpserver:ftplet-api:1.2.0=testCompileClasspath,testRuntimeClasspath
org.apache.ftpserver:ftpserver-core:1.2.0=testCompileClasspath,testRuntimeClasspath
org.apache.httpcomponents:httpclient:4.5.13=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.httpcomponents:httpcore:4.4.15=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.httpcomponents:httpclient:4.5.14=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.httpcomponents:httpcore:4.4.16=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.mina:mina-core:2.1.6=testCompileClasspath,testRuntimeClasspath
org.apache.sshd:sshd-core:2.0.0=testCompileClasspath,testRuntimeClasspath
org.apache.sshd:sshd-scp:2.0.0=testCompileClasspath,testRuntimeClasspath
@@ -356,7 +355,7 @@ org.checkerframework:checker-compat-qual:2.5.5=annotationProcessor,compileClassp
org.checkerframework:checker-qual:2.11.1=checkstyle
org.checkerframework:checker-qual:3.0.0=errorprone,nonprodAnnotationProcessor
org.checkerframework:checker-qual:3.12.0=annotationProcessor,testAnnotationProcessor
org.checkerframework:checker-qual:3.28.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.checkerframework:checker-qual:3.29.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.checkerframework:checker-qual:3.5.0=nonprodRuntime,runtime,soy
org.checkerframework:dataflow:3.0.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
org.checkerframework:javacutil:3.0.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
@@ -374,7 +373,7 @@ org.eclipse.jetty:jetty-server:9.4.49.v20220914=compileClasspath,default,deploy_
org.eclipse.jetty:jetty-servlet:9.4.49.v20220914=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util-ajax:9.4.49.v20220914=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util:9.4.49.v20220914=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.flywaydb:flyway-core:9.10.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.flywaydb:flyway-core:9.12.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.glassfish.jaxb:jaxb-core:4.0.1=nonprodRuntime,runtime
org.glassfish.jaxb:jaxb-runtime:2.3.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.glassfish.jaxb:jaxb-runtime:4.0.1=nonprodRuntime,runtime
@@ -390,10 +389,10 @@ org.hamcrest:hamcrest:2.2=testCompileClasspath,testRuntimeClasspath
org.hibernate.common:hibernate-commons-annotations:5.1.2.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.hibernate:hibernate-core:5.6.14.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.hibernate:hibernate-hikaricp:5.6.14.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jacoco:org.jacoco.agent:0.8.6=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.6=jacocoAnt
org.jacoco:org.jacoco.core:0.8.6=jacocoAnt
org.jacoco:org.jacoco.report:0.8.6=jacocoAnt
org.jacoco:org.jacoco.agent:0.8.7=jacocoAgent,jacocoAnt
org.jacoco:org.jacoco.ant:0.8.7=jacocoAnt
org.jacoco:org.jacoco.core:0.8.7=jacocoAnt
org.jacoco:org.jacoco.report:0.8.7=jacocoAnt
org.javassist:javassist:3.26.0-GA=checkstyle
org.jboss.logging:jboss-logging:3.4.3.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -410,40 +409,40 @@ org.joda:joda-money:1.0.3=compileClasspath,default,deploy_jar,nonprodCompileClas
org.json:json:20160212=soy
org.json:json:20200518=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jsoup:jsoup:1.15.3=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.junit-pioneer:junit-pioneer:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-migrationsupport:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-runner:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-suite-api:1.9.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-suite-commons:1.9.1=testRuntimeClasspath
org.junit:junit-bom:5.9.1=testCompileClasspath,testRuntimeClasspath
org.junit-pioneer:junit-pioneer:2.0.0-RC1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-migrationsupport:5.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-runner:1.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-suite-api:1.9.2=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-suite-commons:1.9.2=testRuntimeClasspath
org.junit:junit-bom:5.9.2=testCompileClasspath,testRuntimeClasspath
org.jvnet.staxex:stax-ex:1.8=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-core:1.10.19=css
org.mockito:mockito-core:4.9.0=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-junit-jupiter:4.9.0=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-core:5.0.0=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-junit-jupiter:5.0.0=testCompileClasspath,testRuntimeClasspath
org.mortbay.jetty:jetty-util:6.1.26=testCompileClasspath,testRuntimeClasspath
org.mortbay.jetty:jetty:6.1.26=testCompileClasspath,testRuntimeClasspath
org.objenesis:objenesis:2.1=css
org.objenesis:objenesis:3.3=testRuntimeClasspath
org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-analysis:7.0=soy
org.ow2.asm:asm-analysis:8.0.1=jacocoAnt
org.ow2.asm:asm-analysis:9.1=jacocoAnt
org.ow2.asm:asm-analysis:9.4=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-commons:7.0=soy
org.ow2.asm:asm-commons:8.0.1=jacocoAnt
org.ow2.asm:asm-commons:9.1=jacocoAnt
org.ow2.asm:asm-commons:9.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-tree:7.0=soy
org.ow2.asm:asm-tree:8.0.1=jacocoAnt
org.ow2.asm:asm-tree:9.1=jacocoAnt
org.ow2.asm:asm-tree:9.4=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-util:7.0=soy
org.ow2.asm:asm-util:9.4=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm:7.0=soy
org.ow2.asm:asm:8.0.1=jacocoAnt
org.ow2.asm:asm:9.1=jacocoAnt
org.ow2.asm:asm:9.4=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.pcollections:pcollections:2.1.2=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
org.plumelib:plume-util:1.0.6=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
@@ -466,8 +465,8 @@ org.slf4j:jcl-over-slf4j:1.7.30=nonprodRuntime,runtime,testRuntimeClasspath
org.slf4j:jul-to-slf4j:1.7.30=nonprodRuntime,runtime,testRuntimeClasspath
org.slf4j:slf4j-api:1.7.30=nonprodRuntime,runtime
org.slf4j:slf4j-api:1.7.36=compileClasspath,nonprodCompileClasspath,nonprodRuntimeClasspath,testCompileClasspath
org.slf4j:slf4j-api:2.0.5=default,deploy_jar,runtimeClasspath,testRuntimeClasspath
org.slf4j:slf4j-jdk14:2.0.5=default,deploy_jar,runtimeClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:2.0.6=default,deploy_jar,runtimeClasspath,testRuntimeClasspath
org.slf4j:slf4j-jdk14:2.0.6=default,deploy_jar,runtimeClasspath,testRuntimeClasspath
org.springframework:spring-core:5.3.18=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.springframework:spring-expression:5.3.18=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.springframework:spring-jcl:5.3.18=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -477,7 +476,7 @@ org.testcontainers:junit-jupiter:1.17.6=testCompileClasspath,testRuntimeClasspat
org.testcontainers:postgresql:1.17.6=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:selenium:1.17.6=testCompileClasspath,testRuntimeClasspath
org.testcontainers:testcontainers:1.17.6=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.threeten:threetenbp:1.6.4=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.threeten:threetenbp:1.6.5=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.tukaani:xz:1.5=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.w3c.css:sac:1.3=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.webjars.npm:viz.js-graphviz-java:2.1.3=nonprodRuntime,runtime,testRuntimeClasspath
@@ -105,10 +105,22 @@ public class BatchModule {
}
@Provides
@Parameter(ExpandRecurringBillingEventsAction.PARAM_CURSOR_TIME)
static Optional<DateTime> provideCursorTime(HttpServletRequest req) {
@Parameter(ExpandRecurringBillingEventsAction.PARAM_START_TIME)
static Optional<DateTime> provideStartTime(HttpServletRequest req) {
return extractOptionalDatetimeParameter(
req, ExpandRecurringBillingEventsAction.PARAM_CURSOR_TIME);
req, ExpandRecurringBillingEventsAction.PARAM_START_TIME);
}
@Provides
@Parameter(ExpandRecurringBillingEventsAction.PARAM_END_TIME)
static Optional<DateTime> provideEndTime(HttpServletRequest req) {
return extractOptionalDatetimeParameter(req, ExpandRecurringBillingEventsAction.PARAM_END_TIME);
}
@Provides
@Parameter(ExpandRecurringBillingEventsAction.PARAM_ADVANCE_CURSOR)
static boolean provideAdvanceCursor(HttpServletRequest req) {
return extractBooleanParameter(req, ExpandRecurringBillingEventsAction.PARAM_ADVANCE_CURSOR);
}
@Provides
@@ -15,58 +15,39 @@
package google.registry.batch;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.newHashSet;
import static google.registry.batch.BatchModule.PARAM_DRY_RUN;
import static google.registry.beam.BeamUtils.createJobName;
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
import static google.registry.model.domain.Period.Unit.YEARS;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_AUTORENEW;
import static google.registry.persistence.transaction.QueryComposer.Comparator.EQ;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.union;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static google.registry.util.DateTimeUtils.earliestOf;
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Range;
import com.google.common.collect.Streams;
import com.google.api.services.dataflow.Dataflow;
import com.google.api.services.dataflow.model.LaunchFlexTemplateParameter;
import com.google.api.services.dataflow.model.LaunchFlexTemplateRequest;
import com.google.api.services.dataflow.model.LaunchFlexTemplateResponse;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import google.registry.beam.billing.ExpandRecurringBillingEventsPipeline;
import google.registry.config.RegistryConfig.Config;
import google.registry.flows.domain.DomainPricingLogic;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.config.RegistryEnvironment;
import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.common.Cursor;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.Period;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.tld.Registry;
import google.registry.persistence.VKey;
import google.registry.request.Action;
import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.util.Clock;
import java.util.List;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import org.joda.time.DateTime;
/**
* An action that expands {@link Recurring} billing events into synthetic {@link OneTime} events.
*
* <p>The cursor used throughout this action (overridden if necessary using the parameter {@code
* cursorTime}) represents the inclusive lower bound on the range of billing times that will be
* expanded as a result of the job (the exclusive upper bound being the execution time of the job).
* An action that kicks off a {@link ExpandRecurringBillingEventsPipeline} dataflow job to expand
* {@link Recurring} billing events into synthetic {@link OneTime} events.
*/
@Action(
service = Action.Service.BACKEND,
@@ -74,303 +55,109 @@ import org.joda.time.DateTime;
auth = Auth.AUTH_INTERNAL_OR_ADMIN)
public class ExpandRecurringBillingEventsAction implements Runnable {
public static final String PARAM_CURSOR_TIME = "cursorTime";
public static final String PARAM_START_TIME = "startTime";
public static final String PARAM_END_TIME = "endTime";
public static final String PARAM_ADVANCE_CURSOR = "advanceCursor";
private static final String PIPELINE_NAME = "expand_recurring_billing_events_pipeline";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Inject Clock clock;
@Inject
@Config("jdbcBatchSize")
int batchSize;
@Parameter(PARAM_DRY_RUN)
boolean isDryRun;
@Inject @Parameter(PARAM_DRY_RUN) boolean isDryRun;
@Inject @Parameter(PARAM_CURSOR_TIME) Optional<DateTime> cursorTimeParam;
@Inject
@Parameter(PARAM_ADVANCE_CURSOR)
boolean advanceCursor;
@Inject
@Parameter(PARAM_START_TIME)
Optional<DateTime> startTimeParam;
@Inject
@Parameter(PARAM_END_TIME)
Optional<DateTime> endTimeParam;
@Inject
@Config("projectId")
String projectId;
@Inject
@Config("defaultJobRegion")
String jobRegion;
@Inject
@Config("beamStagingBucketUrl")
String stagingBucketUrl;
@Inject Dataflow dataflow;
@Inject DomainPricingLogic domainPricingLogic;
@Inject Response response;
@Inject ExpandRecurringBillingEventsAction() {}
@Inject
ExpandRecurringBillingEventsAction() {}
@Override
public void run() {
DateTime executeTime = clock.nowUtc();
DateTime persistedCursorTime =
tm().transact(
() ->
tm().loadByKeyIfPresent(Cursor.createGlobalVKey(RECURRING_BILLING))
.orElse(Cursor.createGlobal(RECURRING_BILLING, START_OF_TIME))
.getCursorTime());
DateTime cursorTime = cursorTimeParam.orElse(persistedCursorTime);
checkArgument(!(isDryRun && advanceCursor), "Cannot advance the cursor in a dry run.");
DateTime endTime = endTimeParam.orElse(clock.nowUtc());
checkArgument(
cursorTime.isBefore(executeTime), "Cursor time must be earlier than execution time.");
logger.atInfo().log(
"Running Recurring billing event expansion for billing time range [%s, %s).",
cursorTime, executeTime);
expandSqlBillingEventsInBatches(executeTime, cursorTime, persistedCursorTime);
}
private void expandSqlBillingEventsInBatches(
DateTime executeTime, DateTime cursorTime, DateTime persistedCursorTime) {
int totalBillingEventsSaved = 0;
long maxProcessedRecurrenceId = 0;
SqlBatchResults sqlBatchResults;
do {
final long prevMaxProcessedRecurrenceId = maxProcessedRecurrenceId;
sqlBatchResults =
tm().transact(
() -> {
Set<String> expandedDomains = newHashSet();
int batchBillingEventsSaved = 0;
long maxRecurrenceId = prevMaxProcessedRecurrenceId;
List<Recurring> recurrings =
tm().query(
"FROM BillingRecurrence "
+ "WHERE eventTime <= :executeTime "
+ "AND eventTime < recurrenceEndTime "
+ "AND id > :maxProcessedRecurrenceId "
+ "AND recurrenceEndTime > :adjustedCursorTime "
+ "ORDER BY id ASC",
Recurring.class)
.setParameter("executeTime", executeTime)
.setParameter("maxProcessedRecurrenceId", prevMaxProcessedRecurrenceId)
.setParameter(
"adjustedCursorTime",
cursorTime.minus(Registry.DEFAULT_AUTO_RENEW_GRACE_PERIOD))
.setMaxResults(batchSize)
.getResultList();
for (Recurring recurring : recurrings) {
if (expandedDomains.contains(recurring.getTargetId())) {
// On the off chance this batch contains multiple recurrences for the same
// domain (which is actually possible if a given domain is quickly renewed
// multiple times in a row), then short-circuit after the first one is
// processed that involves actually expanding a billing event. This is
// necessary because otherwise we get an "Inserted/updated object reloaded"
// error from Hibernate when those billing events would be loaded
// inside a transaction where they were already written. Note, there is no
// actual further work to be done in this case anyway, not unless it has
// somehow been over a year since this action last ran successfully (and if
// that were somehow true, the remaining billing events would still be
// expanded on subsequent runs).
continue;
}
int billingEventsSaved =
expandBillingEvent(
recurring, executeTime, cursorTime, isDryRun, domainPricingLogic);
batchBillingEventsSaved += billingEventsSaved;
if (billingEventsSaved > 0) {
expandedDomains.add(recurring.getTargetId());
}
maxRecurrenceId = Math.max(maxRecurrenceId, recurring.getId());
}
return SqlBatchResults.create(
batchBillingEventsSaved,
maxRecurrenceId,
maxRecurrenceId > prevMaxProcessedRecurrenceId);
});
totalBillingEventsSaved += sqlBatchResults.batchBillingEventsSaved();
maxProcessedRecurrenceId = sqlBatchResults.maxProcessedRecurrenceId();
if (sqlBatchResults.batchBillingEventsSaved() > 0) {
logger.atInfo().log(
"Saved %d billing events in batch (%d total) with max recurrence id %d.",
sqlBatchResults.batchBillingEventsSaved(),
totalBillingEventsSaved,
maxProcessedRecurrenceId);
} else {
// If we're churning through a lot of no-op recurrences that don't need expanding (yet?),
// then only log one no-op every so often as a good balance between letting the user track
// that the action is still running while also not spamming the logs incessantly.
logger.atInfo().atMostEvery(3, TimeUnit.MINUTES).log(
"Processed up to max recurrence id %d (no billing events saved recently).",
maxProcessedRecurrenceId);
}
} while (sqlBatchResults.shouldContinue());
if (!isDryRun) {
logger.atInfo().log("Saved %d total OneTime billing events.", totalBillingEventsSaved);
} else {
logger.atInfo().log(
"Generated %d total OneTime billing events (dry run).", totalBillingEventsSaved);
}
logger.atInfo().log(
"Recurring event expansion %s complete for billing event range [%s, %s).",
isDryRun ? "(dry run) " : "", cursorTime, executeTime);
tm().transact(
() -> {
// Check for the unlikely scenario where the cursor has been altered during the
// expansion.
DateTime currentCursorTime =
tm().loadByKeyIfPresent(Cursor.createGlobalVKey(RECURRING_BILLING))
.orElse(Cursor.createGlobal(RECURRING_BILLING, START_OF_TIME))
.getCursorTime();
if (!currentCursorTime.equals(persistedCursorTime)) {
throw new IllegalStateException(
!endTime.isAfter(clock.nowUtc()), "End time (%s) must be at or before now", endTime);
DateTime startTime =
startTimeParam.orElse(
tm().transact(
() ->
tm().loadByKeyIfPresent(Cursor.createGlobalVKey(RECURRING_BILLING))
.orElse(Cursor.createGlobal(RECURRING_BILLING, START_OF_TIME))
.getCursorTime()));
checkArgument(
startTime.isBefore(endTime),
String.format("Start time (%s) must be before end time (%s)", startTime, endTime));
LaunchFlexTemplateParameter launchParameter =
new LaunchFlexTemplateParameter()
.setJobName(
createJobName(
String.format(
"Current cursor position %s does not match persisted cursor position %s.",
currentCursorTime, persistedCursorTime));
}
if (!isDryRun) {
tm().put(Cursor.createGlobal(RECURRING_BILLING, executeTime));
}
});
}
@AutoValue
abstract static class SqlBatchResults {
abstract int batchBillingEventsSaved();
abstract long maxProcessedRecurrenceId();
abstract boolean shouldContinue();
static SqlBatchResults create(
int batchBillingEventsSaved, long maxProcessedRecurrenceId, boolean shouldContinue) {
return new AutoValue_ExpandRecurringBillingEventsAction_SqlBatchResults(
batchBillingEventsSaved, maxProcessedRecurrenceId, shouldContinue);
"expand-billing-%s", startTime.toString("yyyy-MM-dd't'HH-mm-ss'z'")),
clock))
.setContainerSpecGcsPath(
String.format("%s/%s_metadata.json", stagingBucketUrl, PIPELINE_NAME))
.setParameters(
new ImmutableMap.Builder<String, String>()
.put("registryEnvironment", RegistryEnvironment.get().name())
.put("startTime", startTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"))
.put("endTime", endTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"))
.put("isDryRun", Boolean.toString(isDryRun))
.put("advanceCursor", Boolean.toString(advanceCursor))
.build());
logger.atInfo().log(
"Launching recurring billing event expansion pipeline for event time range [%s, %s)%s.",
startTime,
endTime,
isDryRun ? " in dry run mode" : advanceCursor ? "" : " without advancing the cursor");
try {
LaunchFlexTemplateResponse launchResponse =
dataflow
.projects()
.locations()
.flexTemplates()
.launch(
projectId,
jobRegion,
new LaunchFlexTemplateRequest().setLaunchParameter(launchParameter))
.execute();
logger.atInfo().log("Got response: %s", launchResponse.getJob().toPrettyString());
response.setStatus(SC_OK);
response.setPayload(
String.format(
"Launched recurring billing event expansion pipeline: %s",
launchResponse.getJob().getId()));
} catch (IOException e) {
logger.atWarning().withCause(e).log("Pipeline Launch failed");
response.setStatus(SC_INTERNAL_SERVER_ERROR);
response.setPayload(String.format("Pipeline launch failed: %s", e.getMessage()));
}
}
private static int expandBillingEvent(
Recurring recurring,
DateTime executeTime,
DateTime cursorTime,
boolean isDryRun,
DomainPricingLogic domainPricingLogic) {
ImmutableSet.Builder<OneTime> syntheticOneTimesBuilder = new ImmutableSet.Builder<>();
final Registry tld = Registry.get(getTldFromDomainName(recurring.getTargetId()));
// Determine the complete set of times at which this recurring event should
// occur (up to and including the runtime of the action).
Iterable<DateTime> eventTimes =
recurring
.getRecurrenceTimeOfYear()
.getInstancesInRange(
Range.closed(
recurring.getEventTime(),
earliestOf(recurring.getRecurrenceEndTime(), executeTime)));
// Convert these event times to billing times
final ImmutableSet<DateTime> billingTimes =
getBillingTimesInScope(eventTimes, cursorTime, executeTime, tld);
VKey<Domain> domainKey = VKey.create(Domain.class, recurring.getDomainRepoId());
Iterable<OneTime> oneTimesForDomain;
oneTimesForDomain =
tm().createQueryComposer(OneTime.class)
.where("domainRepoId", EQ, recurring.getDomainRepoId())
.list();
// Determine the billing times that already have OneTime events persisted.
ImmutableSet<DateTime> existingBillingTimes =
getExistingBillingTimes(oneTimesForDomain, recurring);
ImmutableSet.Builder<DomainHistory> historyEntriesBuilder = new ImmutableSet.Builder<>();
// Create synthetic OneTime events for all billing times that do not yet have
// an event persisted.
for (DateTime billingTime : difference(billingTimes, existingBillingTimes)) {
// Construct a new HistoryEntry that parents over the OneTime
DomainHistory historyEntry =
new DomainHistory.Builder()
.setBySuperuser(false)
.setRegistrarId(recurring.getRegistrarId())
.setModificationTime(tm().getTransactionTime())
.setDomain(tm().loadByKey(domainKey))
.setPeriod(Period.create(1, YEARS))
.setReason("Domain autorenewal by ExpandRecurringBillingEventsAction")
.setRequestedByRegistrar(false)
.setType(DOMAIN_AUTORENEW)
// Note: the following statement seems to not be entirely correct as manual renewal
// during the autorenew grace period also closes out the existing recurrence, but in
// that instance the autorenew history entry should still have the transaction records
// for obvious reasons. It can be argued the history entry should always have the
// transaction record, regardless of what happens afterward. If the domain is deleted
// later during the autorenew grace period, another history entry for the delete would
// record that mutation separately, but the previous autorenew should not have its
// history entry retroactively altered, or in this case have the transaction records
// omitted when its created belatedly (when billing time is in scope). However, since
// we will be rewriting this action and only want to do the absolute minimum change to
// fix it for now, we will leave the current logic in place to avoid any unnecessary
// complications.
//
// Don't write a domain transaction record if the recurrence was
// ended prior to the billing time (i.e. a domain was deleted
// during the autorenew grace period).
.setDomainTransactionRecords(
recurring.getRecurrenceEndTime().isBefore(billingTime)
? ImmutableSet.of()
: ImmutableSet.of(
DomainTransactionRecord.create(
tld.getTldStr(),
// We report this when the autorenew grace period
// ends
billingTime,
TransactionReportField.netRenewsFieldFromYears(1),
1)))
.build();
historyEntriesBuilder.add(historyEntry);
DateTime eventTime = billingTime.minus(tld.getAutoRenewGracePeriodLength());
syntheticOneTimesBuilder.add(
new OneTime.Builder()
.setBillingTime(billingTime)
.setRegistrarId(recurring.getRegistrarId())
// Determine the cost for a one-year renewal.
.setCost(
domainPricingLogic
.getRenewPrice(tld, recurring.getTargetId(), eventTime, 1, recurring)
.getRenewCost())
.setEventTime(eventTime)
.setFlags(union(recurring.getFlags(), Flag.SYNTHETIC))
.setDomainHistory(historyEntry)
.setPeriodYears(1)
.setReason(recurring.getReason())
.setSyntheticCreationTime(executeTime)
.setCancellationMatchingBillingEvent(recurring)
.setTargetId(recurring.getTargetId())
.build());
}
Set<DomainHistory> historyEntries = historyEntriesBuilder.build();
Set<OneTime> syntheticOneTimes = syntheticOneTimesBuilder.build();
if (!isDryRun) {
ImmutableSet<ImmutableObject> entitiesToSave =
new ImmutableSet.Builder<ImmutableObject>()
.addAll(historyEntries)
.addAll(syntheticOneTimes)
.build();
tm().putAll(entitiesToSave);
}
return syntheticOneTimes.size();
}
/**
* Filters a set of {@link DateTime}s down to event times that are in scope for a particular
* action run, given the cursor time and the action execution time.
*/
protected static ImmutableSet<DateTime> getBillingTimesInScope(
Iterable<DateTime> eventTimes,
DateTime cursorTime,
DateTime executeTime,
final Registry tld) {
return Streams.stream(eventTimes)
.map(eventTime -> eventTime.plus(tld.getAutoRenewGracePeriodLength()))
.filter(Range.closedOpen(cursorTime, executeTime))
.collect(toImmutableSet());
}
/**
* Determines an {@link ImmutableSet} of {@link DateTime}s that have already been persisted for a
* given recurring billing event.
*/
private static ImmutableSet<DateTime> getExistingBillingTimes(
Iterable<BillingEvent.OneTime> oneTimesForDomain,
final BillingEvent.Recurring recurringEvent) {
return Streams.stream(oneTimesForDomain)
.filter(
billingEvent ->
recurringEvent
.createVKey()
.equals(billingEvent.getCancellationMatchingBillingEvent()))
.map(OneTime::getBillingTime)
.collect(toImmutableSet());
}
}
@@ -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) {
@@ -148,7 +154,7 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
endTime = DateTime.parse(options.getEndTime());
checkArgument(
!endTime.isAfter(clock.nowUtc()),
String.format("End time %s must be on or before now.", endTime));
String.format("End time %s must be at or before now.", endTime));
checkArgument(
startTime.isBefore(endTime),
String.format("[%s, %s) is not a valid window of operation.", startTime, endTime));
@@ -182,7 +188,7 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
+ "AND event_Time < :endTime "
// Recurrence should not close before start time.
+ "AND :startTime < recurrence_end_time "
// Last expansion should happen at least one year before start time.
// Last expansion should happen at least one year before end time.
+ "AND recurrence_last_expansion < :oneYearAgo "
// The recurrence should not close before next expansion time.
+ "AND recurrence_last_expansion + INTERVAL '1 YEAR' < recurrence_end_time",
@@ -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
@@ -239,20 +246,40 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
private void expandOneRecurring(Long recurringId, ImmutableSet.Builder<ImmutableObject> results) {
Recurring recurring = tm().loadByKey(Recurring.createVKey(recurringId));
recurringsInScopeCounter.inc();
Domain domain = tm().loadByKey(Domain.createVKey(recurring.getDomainRepoId()));
Registry tld = Registry.get(domain.getTld());
// Determine the complete set of EventTimes this recurring event should expand to within
// [max(recurrenceLastExpansion + 1 yr, startTime), min(recurrenceEndTime, endTime)).
ImmutableSet<DateTime> eventTimes =
ImmutableSet.copyOf(
recurring
.getRecurrenceTimeOfYear()
.getInstancesInRange(
Range.closedOpen(
latestOf(recurring.getRecurrenceLastExpansion().plusYears(1), startTime),
earliestOf(recurring.getRecurrenceEndTime(), endTime))));
//
// This range should always be legal for recurrings that are returned from the query. However,
// it is possible that the recurring has changed between when the read transformation occurred
// and now. This could be caused by some out-of-process mutations (such as a domain deletion
// closing out a previously open-ended recurrence), or more subtly, Beam could execute the same
// work multiple times due to transient communication issues between workers and the scheduler.
// Such opportunistic retries are OK for pure functional transformations, but can cause
// unexpected behavior when side effects are executed more than once. For example, the
// recurrence_last_expansion field could be updated by a worker after a success expansion, which
// failed to report the status to the scheduler in time, which in turn scheduled another worker
// to work on the same batch. The second worker would see a new recurrence_last_expansion that
// causes the range to be illegal.
//
// The best way to handle any unexpected behavior is to simply drop the recurring from
// expansion, if its new state still calls for an expansion, it would be picked up the next time
// the pipeline runs.
ImmutableSet<DateTime> eventTimes;
try {
eventTimes =
ImmutableSet.copyOf(
recurring
.getRecurrenceTimeOfYear()
.getInstancesInRange(
Range.closedOpen(
latestOf(recurring.getRecurrenceLastExpansion().plusYears(1), startTime),
earliestOf(recurring.getRecurrenceEndTime(), endTime))));
} catch (IllegalArgumentException e) {
return;
}
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
@@ -277,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
@@ -36,7 +36,6 @@ import com.google.api.services.bigquery.model.GetQueryResultsResponse;
import com.google.api.services.bigquery.model.Job;
import com.google.api.services.bigquery.model.JobConfiguration;
import com.google.api.services.bigquery.model.JobConfigurationExtract;
import com.google.api.services.bigquery.model.JobConfigurationLoad;
import com.google.api.services.bigquery.model.JobConfigurationQuery;
import com.google.api.services.bigquery.model.JobReference;
import com.google.api.services.bigquery.model.JobStatistics;
@@ -57,7 +56,6 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import google.registry.bigquery.BigqueryUtils.DestinationFormat;
import google.registry.bigquery.BigqueryUtils.SourceFormat;
import google.registry.bigquery.BigqueryUtils.TableType;
import google.registry.bigquery.BigqueryUtils.WriteDisposition;
import google.registry.util.NonFinalForTesting;
@@ -375,23 +373,6 @@ public class BigqueryConnection implements AutoCloseable {
}
}
/**
* Starts an asynchronous load job to populate the specified destination table with the given
* source URIs and source format. Returns a ListenableFuture that holds the same destination table
* object on success.
*/
public ListenableFuture<DestinationTable> startLoad(
DestinationTable dest, SourceFormat sourceFormat, Iterable<String> sourceUris) {
Job job = new Job()
.setConfiguration(new JobConfiguration()
.setLoad(new JobConfigurationLoad()
.setWriteDisposition(dest.getWriteDisposition().toString())
.setSourceFormat(sourceFormat.toString())
.setSourceUris(ImmutableList.copyOf(sourceUris))
.setDestinationTable(dest.getTableReference())));
return transform(runJobToCompletion(job, dest), this::updateTable, directExecutor());
}
/**
* Starts an asynchronous query job to populate the specified destination table with the results
* of the specified query, or if the table is a view, to update the view to reflect that query.
@@ -25,18 +25,6 @@ import org.joda.time.format.ISODateTimeFormat;
/** Utilities related to Bigquery. */
public class BigqueryUtils {
/** Bigquery modes for schema fields. */
public enum FieldMode {
NULLABLE,
REQUIRED,
REPEATED;
/** Return the name of the field mode as it should appear in the Bigquery schema. */
public String schemaName() {
return name();
}
}
/** Bigquery schema field types. */
public enum FieldType {
STRING,
@@ -44,19 +32,7 @@ public class BigqueryUtils {
FLOAT,
TIMESTAMP,
RECORD,
BOOLEAN;
/** Return the name of the field type as it should appear in the Bigquery schema. */
public String schemaName() {
return name();
}
}
/** Source formats for Bigquery load jobs. */
public enum SourceFormat {
CSV,
NEWLINE_DELIMITED_JSON,
DATASTORE_BACKUP
BOOLEAN
}
/** Destination formats for Bigquery extract jobs. */
@@ -60,7 +60,7 @@ import org.joda.time.Duration;
*
* <p>This class does not represent the total configuration of the Nomulus service. It's <b>only
* meant for settings that need to be configured <i>once</i></b>. Settings which may be subject to
* change in the future, should instead be retrieved from Datastore. The {@link
* change in the future, should instead be retrieved from the database. The {@link
* google.registry.model.tld.Registry Registry} class is one such example of this.
*
* <p>Note: Only settings that are actually configurable belong in this file. It's not a catch-all
@@ -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) {
@@ -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
@@ -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,159 +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: TmchDnlServlet, 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: TmchSmdrlServlet, 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: TmchCrlServlet)
</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]]></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>
<cron>
<url><![CDATA[/_ah/sessioncleanup?clear]]></url>
<description>
Delete up to 100 expired _ah_SESSION entities from Datastore.
</description>
<schedule>every 15 minutes</schedule>
<target>backend</target>
</cron>
</cronentries>
@@ -65,7 +65,6 @@
</queue>
<!-- Queue for tasks that communicate with TMCH MarksDB webserver. -->
<!-- TODO(b/17623181): Delete this once the queue implementation is live and working. -->
<queue>
<name>marksdb</name>
<rate>1/m</rate>
@@ -94,6 +94,12 @@
<url-pattern>/registry-lock-verify</url-pattern>
</servlet-mapping>
<!-- Registrar console endpoints -->
<servlet-mapping>
<servlet-name>frontend-servlet</servlet-name>
<url-pattern>/console-api/*</url-pattern>
</servlet-mapping>
<!-- Security config -->
<security-constraint>
<web-resource-collection>
@@ -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 Datastore. 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 Datastore. 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: TmchDnlServlet, 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: TmchSmdrlServlet, 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: TmchCrlServlet)
</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>
@@ -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>
@@ -0,0 +1,288 @@
<?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>
<!-- TODO: @ptkach add resaveAllEppResourcesPipelineAction https://cs.opensource.google/nomulus/nomulus/+/master:core/src/main/java/google/registry/env/production/default/WEB-INF/cron.xml;l=105 -->
<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,297 +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 Datastore. 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 Datastore. 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: TmchDnlServlet, 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: TmchSmdrlServlet, 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: TmchCrlServlet)
</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]]></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[/_ah/sessioncleanup?clear]]></url>
<description>
Delete up to 100 expired _ah_SESSION entities from Datastore.
</description>
<schedule>every 15 minutes</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>
@@ -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>
@@ -0,0 +1,156 @@
<?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/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>
<!-- TODO: @ptkach add resaveAllEppResourcesPipelineAction https://cs.opensource.google/nomulus/nomulus/+/master:core/src/main/java/google/registry/env/sandbox/default/WEB-INF/cron.xml;l=89 -->
<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,186 +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: TmchDnlServlet, 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: TmchSmdrlServlet, 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: TmchCrlServlet)
</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]]></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[/_ah/sessioncleanup?clear]]></url>
<description>
Delete up to 100 expired _ah_SESSION entities from Datastore.
</description>
<schedule>every 15 minutes</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>
@@ -15,6 +15,8 @@
package google.registry.flows.domain;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.flows.FlowUtils.persistEntityChanges;
import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn;
@@ -52,6 +54,7 @@ import static google.registry.model.tld.Registry.TldState.QUIET_PERIOD;
import static google.registry.model.tld.Registry.TldState.START_DATE_SUNRISE;
import static google.registry.model.tld.label.ReservationType.NAME_COLLISION;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
@@ -61,6 +64,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.net.InternetDomainName;
import google.registry.dns.DnsQueue;
import google.registry.flows.EppException;
import google.registry.flows.EppException.AssociationProhibitsOperationException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
import google.registry.flows.ExtensionManager;
@@ -82,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;
@@ -117,7 +123,10 @@ import google.registry.model.tld.Registry.TldType;
import google.registry.model.tld.label.ReservationType;
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;
import javax.inject.Inject;
@@ -156,6 +165,7 @@ import org.joda.time.Duration;
* @error {@link DomainFlowTmchUtils.NoMarksFoundMatchingDomainException}
* @error {@link DomainFlowTmchUtils.FoundMarkNotYetValidException}
* @error {@link DomainFlowTmchUtils.FoundMarkExpiredException}
* @error {@link DomainFlowTmchUtils.SignedMarkRevokedErrorException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link DomainFlowUtils.AcceptedTooLongAgoException}
* @error {@link DomainFlowUtils.BadDomainNameCharacterException}
@@ -270,6 +280,13 @@ 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(
domainName, allocationToken, eppInput.getSingleExtension(MetadataExtension.class));
@@ -327,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);
@@ -367,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)
@@ -387,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) {
@@ -434,6 +458,36 @@ public final class DomainCreateFlow implements TransactionalFlow {
.build();
}
private Optional<AllocationToken> checkForDefaultToken(
Registry registry, DomainCommand.Create command) throws EppException {
Map<VKey<AllocationToken>, Optional<AllocationToken>> tokens =
AllocationToken.getAll(registry.getDefaultPromoTokens());
ImmutableList<Optional<AllocationToken>> tokenList =
registry.getDefaultPromoTokens().stream()
.map(tokens::get)
.filter(Optional::isPresent)
.collect(toImmutableList());
checkState(
!isNullOrEmpty(tokenList),
"Failure while loading default TLD promotions from the database");
// Check if any of the tokens are valid for this domain registration
for (Optional<AllocationToken> token : tokenList) {
try {
AllocationTokenFlowUtils.validateToken(
InternetDomainName.from(command.getDomainName()),
token.get(),
registrarId,
tm().getTransactionTime());
} catch (AssociationProhibitsOperationException e) {
// Allocation token was not valid for this registration, continue to check the next token in
// the list
continue;
}
// Only use the first valid token in the list
return token;
}
return Optional.empty();
}
/**
* Verifies that signed marks are only sent during sunrise.
*
@@ -657,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(
@@ -79,9 +79,10 @@ import org.joda.time.DateTime;
* transfer is automatically approved. Within that window, this flow allows the losing client to
* explicitly approve the transfer request, which then becomes effective immediately.
*
* <p>When the transfer was requested, poll messages and billing events were saved to Datastore with
* timestamps such that they only would become active when the transfer period passed. In this flow,
* those speculative objects are deleted and replaced with new ones with the correct approval time.
* <p>When the transfer was requested, poll messages and billing events were saved to the database
* with timestamps such that they only would become active when the transfer period passed. In this
* flow, those speculative objects are deleted and replaced with new ones with the correct approval
* time.
*
* @error {@link google.registry.flows.FlowUtils.NotLoggedInException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
@@ -62,9 +62,9 @@ import org.joda.time.DateTime;
* transfer is automatically approved. Within that window, this flow allows the gaining client to
* withdraw the transfer request.
*
* <p>When the transfer was requested, poll messages and billing events were saved to Datastore with
* timestamps such that they only would become active when the transfer period passed. In this flow,
* those speculative objects are deleted.
* <p>When the transfer was requested, poll messages and billing events were saved to the database
* with timestamps such that they only would become active when the transfer period passed. In this
* flow, those speculative objects are deleted.
*
* @error {@link google.registry.flows.FlowUtils.NotLoggedInException}
* @error {@link google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException}
@@ -91,7 +91,7 @@ import org.joda.time.DateTime;
* by the losing registrar or rejected, and the gaining registrar can also cancel the transfer
* request.
*
* <p>When a transfer is requested, poll messages and billing events are saved to Datastore with
* <p>When a transfer is requested, poll messages and billing events are saved to the database with
* timestamps such that they only become active when the server-approval period passes. Keys to
* these speculative objects are saved in the domain's transfer data, and on explicit approval,
* rejection or cancellation of the request, they will be deleted (and in the approval case,
@@ -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(),
@@ -307,6 +307,13 @@ public final class DomainUpdateFlow implements TransactionalFlow {
}
}
/**
* Checks whether the new state of the domain is valid.
*
* <p>Note: Before adding or amending conditions, existing data has to be verified for being
* compliant with the additions or amendments, otherwise existing data can become invalid and
* cause Domain update failure.
*/
private void validateNewState(Domain newDomain) throws EppException {
validateRequiredContactsPresent(newDomain.getRegistrant(), newDomain.getContacts());
validateDsData(newDomain.getDsData());
@@ -108,7 +108,7 @@ public class AllocationTokenFlowUtils {
*
* @throws EppException if the token is invalid in any way
*/
private static void validateToken(
public static void validateToken(
InternetDomainName domainName, AllocationToken token, String registrarId, DateTime now)
throws EppException {
@@ -46,9 +46,9 @@ import org.joda.time.DateTime;
* An EPP flow for acknowledging {@link PollMessage}s.
*
* <p>Registrars refer to poll messages using an externally visible id generated by {@link
* PollMessageExternalKeyConverter}. One-time poll messages are deleted from Datastore once they are
* ACKed, whereas autorenew poll messages are simply marked as read, and won't be delivered again
* until the next year of their recurrence.
* PollMessageExternalKeyConverter}. One-time poll messages are deleted from the database once they
* are ACKed, whereas autorenew poll messages are simply marked as read, and won't be delivered
* again until the next year of their recurrence.
*
* @error {@link PollAckFlow.InvalidMessageIdException}
* @error {@link PollAckFlow.MessageDoesNotExistException}
@@ -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
@@ -51,7 +51,7 @@ import org.bouncycastle.openpgp.PGPPublicKey;
/**
* The {@link SecretManagerKeyringUpdater} accumulates updates to a {@link SecretManagerKeyring} and
* persists them to KMS and Datastore when closed.
* persists them to Cloud Secret Manager when closed.
*/
public final class SecretManagerKeyringUpdater {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -125,7 +125,7 @@ public final class SecretManagerKeyringUpdater {
}
/**
* Persists the secrets in the Secret Manager (primary) and the Datastore (secondary).
* Persists the secrets in the Secret Manager.
*
* <p>Updates to the Secret Manager are not transactional. If an error happens, the successful
* updates are not reverted; unwritten updates are aborted. This is not a problem right now, since
@@ -22,14 +22,14 @@ import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.base.Supplier;
import java.time.Duration;
/** Utility methods related to caching Datastore entities. */
/** Utility methods related to caching database entities. */
public class CacheUtils {
/**
* Memoize a supplier, with a short expiration specified in the environment config.
*
* <p>Use this for things that might change while code is running. (For example, the various lists
* downloaded from the TMCH get updated in Datastore and the caches need to be refreshed.)
* downloaded from the TMCH get updated in the database and the caches need to be refreshed.)
*/
public static <T> Supplier<T> memoizeWithShortExpiration(Supplier<T> original) {
return tryMemoizeWithExpiration(getSingletonCacheRefreshDuration(), original);
@@ -16,6 +16,7 @@ package google.registry.model;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.gson.annotations.Expose;
import javax.annotation.Nullable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@@ -23,11 +24,12 @@ import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import org.joda.time.DateTime;
/** A timestamp that auto-updates when first saved to Datastore. */
/** A timestamp that auto-updates when first saved to the database. */
@Embeddable
public class CreateAutoTimestamp extends ImmutableObject implements UnsafeSerializable {
@Column(nullable = false)
@Expose
DateTime creationTime;
@PrePersist
@@ -31,8 +31,8 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.annotations.VisibleForTesting;
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.model.annotations.IdAllocation;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.transfer.TransferData;
import google.registry.persistence.VKey;
@@ -66,7 +66,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
*
* @see <a href="https://tools.ietf.org/html/rfc5730">RFC 5730</a>
*/
@IdAllocation @Transient String repoId;
@Expose @Transient String repoId;
/**
* The ID of the registrar that is currently sponsoring this resource.
@@ -74,7 +74,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
* <p>This can be null in the case of pre-Registry-3.0-migration history objects with null
* resource fields.
*/
String currentSponsorRegistrarId;
@Expose String currentSponsorRegistrarId;
/**
* The ID of the registrar that created this resource.
@@ -82,7 +82,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
* <p>This can be null in the case of pre-Registry-3.0-migration history objects with null
* resource fields.
*/
String creationRegistrarId;
@Expose String creationRegistrarId;
/**
* The ID of the registrar that last updated this resource.
@@ -91,7 +91,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
* edits; it only includes EPP-visible modifications such as {@literal <update>}. Can be null if
* the resource has never been modified.
*/
String lastEppUpdateRegistrarId;
@Expose String lastEppUpdateRegistrarId;
/**
* The time when this resource was created.
@@ -105,6 +105,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
*/
// Need to override the default non-null column attribute.
@AttributeOverride(name = "creationTime", column = @Column)
@Expose
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
/**
@@ -129,10 +130,10 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
* edits; it only includes EPP-visible modifications such as {@literal <update>}. Can be null if
* the resource has never been modified.
*/
DateTime lastEppUpdateTime;
@Expose DateTime lastEppUpdateTime;
/** Status values associated with this resource. */
Set<StatusValue> statuses;
@Expose Set<StatusValue> statuses;
public String getRepoId() {
return repoId;
@@ -89,14 +89,14 @@ public final class EppResourceUtils {
}
/**
* Loads the last created version of an {@link EppResource} from Datastore by foreign key.
* Loads the last created version of an {@link EppResource} from the database by foreign key.
*
* <p>Returns empty if no resource with this foreign key was ever created, or if the most recently
* created resource was deleted before time "now".
*
* <p>Loading an {@link EppResource} by itself is not sufficient to know its current state since
* it may have various expirable conditions and status values that might implicitly change its
* state as time progresses even if it has not been updated in Datastore. Rather, the resource
* state as time progresses even if it has not been updated in the database. Rather, the resource
* must be combined with a timestamp to view its current state. We use a global last updated
* timestamp on the resource's entity group (which is essentially free since all writes to the
* entity group must be serialized anyways) to guarantee monotonically increasing write times, and
@@ -330,7 +330,7 @@ public final class EppResourceUtils {
/**
* Returns a set of {@link VKey} for domains that reference a specified contact or host.
*
* <p>This is an eventually consistent query if used for Datastore.
* <p>This is an eventually consistent query if used for the database.
*
* @param key the referent key
* @param now the logical time of the check
@@ -50,7 +50,7 @@ import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Class to help build and persist all the OT&amp;E entities in Datastore.
* Class to help build and persist all the OT&amp;E entities in the database.
*
* <p>This includes the TLDs (Registries), Registrars, and the RegistrarContacts that can access the
* web console.
@@ -18,9 +18,7 @@ import java.io.Serializable;
/**
* Marker interface for Nomulus entities whose serialization are implemented in a fragile way. These
* entities are made {@link Serializable} so that they can be passed between JVMs. The intended use
* case is BEAM pipeline-based cross-database data validation between Datastore and Cloud SQL during
* the migration. Note that only objects loaded from the SQL database need serialization support.
* entities are made {@link Serializable} so that they can be passed between JVMs.
*
* <p>All entities implementing this interface take advantage of the fact that all Java collection
* classes we use, either directly or indirectly, including those in Java libraries, Guava, and
@@ -29,5 +27,4 @@ import java.io.Serializable;
* <p>The {@code serialVersionUID} field has also been omitted in the implementing classes, since
* they are not used for persistence.
*/
// TODO(b/203609782): either remove this interface or fix implementors post migration.
public interface UnsafeSerializable extends Serializable {}
@@ -25,7 +25,7 @@ import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import org.joda.time.DateTime;
/** A timestamp that auto-updates on each save to Datastore/Cloud SQL. */
/** A timestamp that auto-updates on each save to Cloud SQL. */
@Embeddable
public class UpdateAutoTimestamp extends ImmutableObject implements UnsafeSerializable {
@@ -312,7 +312,7 @@ public abstract class BillingEvent extends ImmutableObject
Integer periodYears;
/**
* For {@link Flag#SYNTHETIC} events, when this event was persisted to Datastore (i.e. the
* For {@link Flag#SYNTHETIC} events, when this event was persisted to the database (i.e. the
* cursor position at the time the recurrence expansion job was last run). In the event a job
* needs to be undone, a query on this field will return the complete set of potentially bad
* events.
@@ -52,8 +52,7 @@ public class Cursor extends UpdateAutoTimestampEntity {
/** The scope of a global cursor. A global cursor is a cursor that is not specific to one tld. */
public static final String GLOBAL = "GLOBAL";
/** The types of cursors, used as the string id field for each cursor in Datastore. */
/** The types of cursors, used as the string id field for each cursor in the database. */
public enum CursorType {
/** Cursor for ensuring rolling transactional isolation of BRDA staging operation. */
BRDA(true),
@@ -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,13 +224,15 @@ 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. */
@VisibleForTesting
static TimedTransitionProperty<MigrationState> getUncached() {
return tm().transactWithoutBackup(
return tm().transact(
() -> {
try {
return tm().loadSingleton(DatabaseMigrationStateSchedule.class)
@@ -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();
@@ -56,7 +56,7 @@ public class ContactBase extends EppResource
* Unique identifier for this contact.
*
* <p>This is only unique in the sense that for any given lifetime specified as the time range
* from (creationTime, deletionTime) there can only be one contact in Datastore with this id.
* from (creationTime, deletionTime) there can only be one contact in the database with this id.
* However, there can be many contacts with the same id and non-overlapping lifetimes.
*/
String contactId;
@@ -122,8 +122,8 @@ public class ContactCommand {
* Unique identifier for this contact.
*
* <p>This is only unique in the sense that for any given lifetime specified as the time range
* from (creationTime, deletionTime) there can only be one contact in Datastore with this
* id. However, there can be many contacts with the same id and non-overlapping lifetimes.
* from (creationTime, deletionTime) there can only be one contact in the database with this id.
* However, there can be many contacts with the same id and non-overlapping lifetimes.
*/
@XmlElement(name = "id")
String contactId;
@@ -28,7 +28,7 @@ import javax.xml.bind.annotation.XmlEnumValue;
*
* <p>A contact association on a domain consists of the contact key and the contact "type", which is
* the designated role of this contact with respect to this domain. When converting to and from EPP
* XML, we use {@link ForeignKeyedDesignatedContact} to replace the contact's Datastore key with its
* XML, we use {@link ForeignKeyedDesignatedContact} to replace the contact's primary key with its
* foreign key, since that is what EPP exposes.
*
* <p>Note one could in principle store contact foreign keys here in addition to keys, unlike the
@@ -58,7 +58,7 @@ 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"),
@Index(columnList = "transfer_billing_recurrence_id")
@@ -199,7 +199,7 @@ 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));
}
}
@@ -40,7 +40,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import google.registry.dns.RefreshDnsAction;
import com.google.gson.annotations.Expose;
import google.registry.flows.ResourceFlowUtils;
import google.registry.model.EppResource;
import google.registry.model.EppResource.ResourceWithTransferData;
@@ -61,6 +61,8 @@ import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import google.registry.tldconfig.idn.IdnLabelValidator;
import google.registry.tmch.LordnTaskUtils.LordnPhase;
import google.registry.tmch.NordnUploadAction;
import google.registry.util.CollectionUtils;
import google.registry.util.DateTimeUtils;
import java.util.HashSet;
@@ -76,6 +78,8 @@ import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
@@ -118,20 +122,20 @@ public class DomainBase extends EppResource
*
* @invariant domainName == domainName.toLowerCase(Locale.ENGLISH)
*/
String domainName;
@Expose String domainName;
/** The top level domain this is under, de-normalized from {@link #domainName}. */
String tld;
/** References to hosts that are the nameservers for the domain. */
@Transient Set<VKey<Host>> nsHosts;
@Expose @Transient Set<VKey<Host>> nsHosts;
/** Contacts. */
VKey<Contact> adminContact;
@Expose VKey<Contact> adminContact;
VKey<Contact> billingContact;
VKey<Contact> techContact;
VKey<Contact> registrantContact;
@Expose VKey<Contact> billingContact;
@Expose VKey<Contact> techContact;
@Expose VKey<Contact> registrantContact;
/** Authorization info (aka transfer secret) of the domain. */
@Embedded
@@ -172,10 +176,10 @@ public class DomainBase extends EppResource
String idnTableName;
/** Fully qualified host names of this domain's active subordinate hosts. */
Set<String> subordinateHosts;
@Expose Set<String> subordinateHosts;
/** When this domain's registration will expire. */
DateTime registrationExpirationTime;
@Expose DateTime registrationExpirationTime;
/**
* The poll message associated with this domain being deleted.
@@ -227,7 +231,7 @@ public class DomainBase extends EppResource
*
* <p>Can be null if the resource has never been transferred.
*/
DateTime lastTransferTime;
@Expose DateTime lastTransferTime;
/**
* When the domain's autorenewal status will expire.
@@ -247,35 +251,27 @@ public class DomainBase extends EppResource
DateTime autorenewEndTime;
/**
* When this domain's DNS was requested to be refreshed, or null if its DNS is up-to-date.
* Which Lordn phase the domain is in after it is created but before the Nordn upload has
* processed the domain.
*
* <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>This will almost always be {@code NONE} except in the interval between when a domain that
* contains a signed mark or claims notice has been created, and when {@link NordnUploadAction}
* runs, which includes the domain in the CSV uploaded to TMCH and sets this back to {@code NONE}.
*
* <p>Note that this is a Cloud SQL-based replacement for the {@code dns-pull} task queue. The
* domains that have a non-null value for this field should be exactly the same as the tasks that
* would be in the {@code dns-pull} queue. Because this is Cloud SQL-specific, it is omitted from
* Datastore.
*
* <p>Note that in the {@link DomainHistory} table this value means something slightly different:
* It means that the given domain action requested a DNS update. Unlike on the {@code Domain}
* 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.
* <p>Note that in the {@code DomainHistory} table this value means something slightly different:
* It means that the given domain was created with a signed mark ({@code SUNRISE} or a claims
* notice ({@code CLAIMS}. Unlike on the {@code Domain} table, this value is not then subsequently
* set back to {@code NONE} once the Nordn upload is complete; rather, it remains as a permanent
* record of when which phase the domain is in when created.
*/
// TODO(mcilwain): Start using this field once we are further along in the DB migration.
DateTime dnsRefreshRequestTime;
@Enumerated(EnumType.STRING)
LordnPhase lordnPhase = LordnPhase.NONE;
/** The {@link AllocationToken} for the package this domain is currently a part of. */
@Nullable VKey<AllocationToken> currentPackageToken;
/**
* Returns the DNS refresh request time iff this domain's DNS needs refreshing, otherwise absent.
*/
public Optional<DateTime> getDnsRefreshRequestTime() {
return Optional.ofNullable(dnsRefreshRequestTime);
public LordnPhase getLordnPhase() {
return lordnPhase;
}
public ImmutableSet<String> getSubordinateHosts() {
@@ -485,7 +481,7 @@ public class DomainBase extends EppResource
.setCurrentPackageToken(null);
if (transferData.getTransferPeriod().getValue() == 1) {
// Set the grace period using a key to the pre-scheduled transfer billing event. Not using
// GracePeriod.forBillingEvent() here in order to avoid the actual Datastore fetch.
// GracePeriod.forBillingEvent() here in order to avoid the actual fetch.
builder.setGracePeriods(
ImmutableSet.of(
GracePeriod.create(
@@ -862,8 +858,8 @@ public class DomainBase extends EppResource
return thisCastToDerived();
}
public B setDnsRefreshRequestTime(Optional<DateTime> dnsRefreshRequestTime) {
getInstance().dnsRefreshRequestTime = dnsRefreshRequestTime.orElse(null);
public B setLordnPhase(LordnPhase lordnPhase) {
getInstance().lordnPhase = lordnPhase;
return thisCastToDerived();
}
@@ -154,7 +154,7 @@ public class DomainHistory extends HistoryEntry {
*
* <p>This will be empty for any DomainHistory/HistoryEntry generated before this field was added
* (mid-2017), as well as any action that does not generate billable events (e.g. contact/host
* updates). *
* updates).
*/
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinColumn(name = "historyRevisionId", referencedColumnName = "historyRevisionId")
@@ -23,10 +23,10 @@ import javax.xml.bind.annotation.XmlValue;
*
* <p>This type is used on the wire for EPP XML, where only the contact ID (foreign key) is exposed.
* This is converted to and from the persisted type, {@link DesignatedContact}, which stores the
* Datastore key instead of the foreign key.
* primary key instead of the foreign key.
*
* @see <a href="http://tools.ietf.org/html/rfc5731#section-2.2">
* RFC 5731 - EPP Domain Name Mapping - Contact and Client Identifiers</a>
* @see <a href="http://tools.ietf.org/html/rfc5731#section-2.2">RFC 5731 - EPP Domain Name Mapping
* - Contact and Client Identifiers</a>
*/
public class ForeignKeyedDesignatedContact extends ImmutableObject {
@XmlAttribute(required = true)
@@ -37,7 +37,7 @@ import org.joda.time.DateTime;
* A domain grace period with an expiration time.
*
* <p>When a grace period expires, it is lazily removed from the {@link Domain} the next time the
* resource is loaded from Datastore.
* resource is loaded from the database.
*/
@Entity
@Table(
@@ -84,8 +84,8 @@ public class GracePeriod extends GracePeriodBase {
* Creates a GracePeriod for an (optional) OneTime billing event.
*
* <p>Normal callers should always use {@link #forBillingEvent} instead, assuming they do not need
* to avoid loading the BillingEvent from Datastore. This method should typically be called only
* from test code to explicitly construct GracePeriods.
* to avoid loading the BillingEvent from the database. This method should typically be called
* only from test code to explicitly construct GracePeriods.
*/
public static GracePeriod create(
GracePeriodStatus type,
@@ -102,8 +102,8 @@ public class GracePeriod extends GracePeriodBase {
* #gracePeriodId}.
*
* <p>Normal callers should always use {@link #forBillingEvent} instead, assuming they do not need
* to avoid loading the BillingEvent from Datastore. This method should typically be called only
* from test code to explicitly construct GracePeriods.
* to avoid loading the BillingEvent from the database. This method should typically be called
* only from test code to explicitly construct GracePeriods.
*/
@VisibleForTesting
public static GracePeriod create(
@@ -16,16 +16,22 @@ package google.registry.model.domain.token;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration;
import static google.registry.model.domain.token.AllocationToken.TokenStatus.CANCELLED;
import static google.registry.model.domain.token.AllocationToken.TokenStatus.ENDED;
import static google.registry.model.domain.token.AllocationToken.TokenStatus.NOT_STARTED;
import static google.registry.model.domain.token.AllocationToken.TokenStatus.VALID;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.forceEmptyToNull;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
@@ -34,6 +40,7 @@ import com.google.common.collect.Range;
import google.registry.flows.EppException;
import google.registry.flows.domain.DomainFlowUtils;
import google.registry.model.Buildable;
import google.registry.model.CacheUtils;
import google.registry.model.CreateAutoTimestamp;
import google.registry.model.UpdateAutoTimestampEntity;
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
@@ -41,6 +48,7 @@ import google.registry.model.common.TimedTransitionProperty;
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
import google.registry.persistence.VKey;
import google.registry.persistence.WithVKey;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
@@ -267,6 +275,39 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
return STATIC_TOKEN_BEHAVIORS.getOrDefault(token, TokenBehavior.DEFAULT);
}
public static Optional<AllocationToken> get(VKey<AllocationToken> key) {
return ALLOCATION_TOKENS_CACHE.get(key);
}
public static Map<VKey<AllocationToken>, Optional<AllocationToken>> getAll(
ImmutableList<VKey<AllocationToken>> keys) {
return ALLOCATION_TOKENS_CACHE.getAll(keys);
}
/** A cache that loads the {@link AllocationToken} object for a given AllocationToken VKey. */
private static final LoadingCache<VKey<AllocationToken>, Optional<AllocationToken>>
ALLOCATION_TOKENS_CACHE =
CacheUtils.newCacheBuilder(getSingletonCacheRefreshDuration())
.build(
new CacheLoader<VKey<AllocationToken>, Optional<AllocationToken>>() {
@Override
public Optional<AllocationToken> load(VKey<AllocationToken> key) {
return tm().transact(() -> tm().loadByKeyIfPresent(key));
}
@Override
public Map<VKey<AllocationToken>, Optional<AllocationToken>> loadAll(
Iterable<? extends VKey<AllocationToken>> keys) {
ImmutableSet<VKey<AllocationToken>> keySet = ImmutableSet.copyOf(keys);
return tm().transact(
() ->
keySet.stream()
.collect(
toImmutableMap(
key -> key, key -> tm().loadByKeyIfPresent(key))));
}
});
@Override
public VKey<AllocationToken> createVKey() {
if (!AllocationToken.TokenBehavior.DEFAULT.equals(getTokenBehavior())) {
@@ -60,7 +60,7 @@ public enum StatusValue implements EppEnum {
/**
* A status for a resource has an incoming reference from an active domain.
*
* <p>LINKED is a "virtual" status value that should never be persisted to Datastore on any
* <p>LINKED is a "virtual" status value that should never be persisted to the database on any
* resource. It must be computed on the fly when we need it, as the set of domains using a
* resource can change at any time.
*/
@@ -13,7 +13,7 @@
// limitations under the License.
/**
* Nomulus Datastore model common/shared classes.
* Nomulus data model common/shared classes.
*
* <p>This package is intended to hold classes which are shared across multiple XML namespaces. As
* such, no default namespace is declared in this package, and all objects in this package should be
@@ -28,7 +28,7 @@ import javax.persistence.Table;
/**
* A persistable Host resource including mutable and non-mutable fields.
*
* <p>The {@link javax.persistence.Id} of the Host is the repoId.
* <p>The {@link Id} of the Host is the repoId.
*/
@Entity(name = "Host")
@Table(
@@ -48,7 +48,7 @@ import javax.persistence.Table;
@Index(columnList = "hostName"),
@Index(columnList = "creationTime"),
@Index(columnList = "deletionTime"),
@Index(columnList = "currentSponsorRegistrarId")
@Index(columnList = "currentSponsorRegistrarId"),
})
@ExternalMessagingName("host")
@WithVKey(String.class)
@@ -81,7 +81,7 @@ public class Host extends HostBase implements ForeignKeyedEppResource {
}
public Builder copyFrom(HostBase hostBase) {
return this.setCreationRegistrarId(hostBase.getCreationRegistrarId())
return setCreationRegistrarId(hostBase.getCreationRegistrarId())
.setCreationTime(hostBase.getCreationTime())
.setDeletionTime(hostBase.getDeletionTime())
.setHostName(hostBase.getHostName())
@@ -57,7 +57,7 @@ public class HostBase extends EppResource {
* Fully qualified hostname, which is a unique identifier for this host.
*
* <p>This is only unique in the sense that for any given lifetime specified as the time range
* from (creationTime, deletionTime) there can only be one host in Datastore with this name.
* from (creationTime, deletionTime) there can only be one host in the database with this name.
* However, there can be many hosts with the same name and non-overlapping lifetimes.
*/
String hostName;
@@ -67,7 +67,7 @@ import org.joda.time.DateTime;
*
* <p>Poll messages are not delivered until their {@link #eventTime} has passed. Poll messages can
* be speculatively enqueued for future delivery, and then modified or deleted before that date has
* passed. Unlike most other entities in Datastore, which are marked as deleted but otherwise
* passed. Unlike most other entities in the database, which are marked as deleted but otherwise
* retained for historical purposes, poll messages are truly deleted once they have been delivered
* and ACKed.
*
@@ -337,7 +337,8 @@ public abstract class PollMessage extends ImmutableObject
/**
* A one-time poll message.
*
* <p>One-time poll messages are deleted from Datastore once they have been delivered and ACKed.
* <p>One-time poll messages are deleted from the database once they have been delivered and
* ACKed.
*/
@Entity
@DiscriminatorValue("ONE_TIME")
@@ -25,7 +25,7 @@ import javax.inject.Inject;
import org.joda.money.Money;
import org.joda.time.DateTime;
/** A premium list pricing engine that stores static pricing information in Datastore entities. */
/** A premium list pricing engine that stores static pricing information in database entities. */
public final class StaticPremiumListPricingEngine implements PremiumPricingEngine {
/** The name of the pricing engine, as used in {@code Registry.pricingEngineClassName}. */
@@ -37,7 +37,7 @@ import org.joda.time.DateTime;
import org.joda.time.LocalDate;
/**
* Datastore entity for tracking RDE revisions.
* Entity for tracking RDE revisions.
*
* <p>This class is used by the RDE staging, upload, and reporting systems to determine the revision
* that should be used in the generated filename. It also determines whether or not a {@code resend}
@@ -102,10 +102,10 @@ public final class RdeRevision extends UpdateAutoTimestampEntity {
* Sets the revision ID for a given triplet.
*
* <p>This method verifies that the current revision is {@code revision - 1}, or that the object
* does not exist in Datastore if {@code revision == 0}.
* does not exist in the database if {@code revision == 0}.
*
* @throws IllegalStateException if not in a transaction
* @throws VerifyException if Datastore state doesn't meet the above criteria
* @throws VerifyException if the state doesn't meet the above criteria
*/
public static void saveRevision(String tld, DateTime date, RdeMode mode, int revision) {
checkArgument(revision >= 0, "Negative revision: %s", revision);
@@ -217,8 +217,8 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
* on its length.
*
* <p>NB: We are assuming that this field is unique across all registrar entities. This is not
* formally enforced in Datastore, but should be enforced by ICANN in that no two registrars will
* be accredited with the same name.
* formally enforced in the database, but should be enforced by ICANN in that no two registrars
* will be accredited with the same name.
*
* @see <a href="http://www.icann.org/registrar-reports/accredited-list.html">ICANN-Accredited
* Registrars</a>
@@ -930,7 +930,7 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
return email;
}
/** Loads all registrar entities directly from Datastore. */
/** Loads all registrar entities directly from the database. */
public static Iterable<Registrar> loadAll() {
return tm().transact(() -> tm().loadAllOf(Registrar.class));
}
@@ -947,7 +947,7 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
.collect(toImmutableSet());
}
/** Loads and returns a registrar entity by its id directly from Datastore. */
/** Loads and returns a registrar entity by its id directly from the database. */
public static Optional<Registrar> loadByRegistrarId(String registrarId) {
checkArgument(!Strings.isNullOrEmpty(registrarId), "registrarId must be specified");
return tm().transact(() -> tm().loadByKeyIfPresent(createVKey(registrarId)));
@@ -121,21 +121,7 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
*/
Set<Type> types;
/**
* A GAIA email address that was assigned to the registrar for console login purpose.
*
* <p>We used to store the GAE user ID directly to identify the logged-in user in the registrar
* console, and relied on a hacky trick with datastore to get the ID from the email address when
* creating a {@link RegistrarPoc}. We switched to using the login email directly as each
* registrar is assigned a unique email address that is immutable (to them at least), so it is as
* good as an identifier as the ID itself, and it allows us to get rid of the datastore
* dependency.
*
* <p>We backfilled all login email addresses for existing {@link RegistrarPoc}s that have a
* non-null GAE user ID. The backfill is done by first trying the {@link #emailAddress} field,
* then trying {@link #registrarId}+"@known-dasher_domain" and picking the ones that converted to
* the existing ID stored in the database.
*/
/** A GAIA email address that was assigned to the registrar for console login purpose. */
String loginEmailAddress;
/**
@@ -55,10 +55,13 @@ public class DomainTransactionRecord extends ImmutableObject
@Column(nullable = false)
String tld;
// The following two fields are exposed in this entity to support bulk-loading in Cloud SQL by the
// Datastore-SQL validation. They are excluded from equality check since they are not set in
// Datastore.
// TODO(b/203609782): post migration, decide whether to keep these two fields.
// The following two fields are marked as insignificant because they are only used to map the set
// of DomainTransactionRecords of a DomainHistory to the rows in the DomainTransactionRecord
// table. They are auto-populated when the DomainHistory is persisted into the database (due to
// the one-to-many mapping) and are foreign key constrained. More importantly, they cannot be set
// directly in the code. We therefore do not need to compare them for equality checks, and we
// would have to introduce setters only to set them in tests (and change a lot of test code) if
// we remove the annotation.
@Insignificant String domainRepoId;
@Insignificant Long historyRevisionId;
@@ -88,8 +88,7 @@ public class Lock extends ImmutableObject implements Serializable {
* <p>See {@link RequestStatusCheckerImpl#getLogId} for details about how it's created in
* practice.
*/
@Column(nullable = false)
String requestLogId;
@Column String requestLogId;
/** When the lock can be considered implicitly released. */
@Column(nullable = false)
@@ -240,7 +239,7 @@ public class Lock extends ImmutableObject implements Serializable {
return AcquireResult.create(now, lock, newLock, lockState);
};
AcquireResult acquireResult = tm().transactWithoutBackup(lockAcquirer);
AcquireResult acquireResult = tm().transact(lockAcquirer);
logAcquireResult(acquireResult);
lockMetrics.recordAcquire(resourceName, scope, acquireResult.lockState());
@@ -277,7 +276,7 @@ public class Lock extends ImmutableObject implements Serializable {
}
return null;
};
tm().transactWithoutBackup(lockReleaser);
tm().transact(lockReleaser);
}
static class LockId extends ImmutableObject implements Serializable {
@@ -54,7 +54,7 @@ public class ServerSecret extends CrossTldSingleton {
});
}
/** Returns the global ServerSecret instance, creating it if one isn't already in Datastore. */
/** Returns the global ServerSecret instance, creating it if one isn't already in the database. */
public static ServerSecret get() {
return CACHE.get(ServerSecret.class);
}
@@ -84,7 +84,7 @@ public final class Registries {
return ImmutableSet.copyOf(filterValues(cache.get(), equalTo(type)).keySet());
}
/** Returns the Registry entities themselves of the given type loaded fresh from Datastore. */
/** Returns the Registry entities themselves of the given type loaded fresh from the database. */
public static ImmutableSet<Registry> getTldEntitiesOfType(TldType type) {
return Registry.get(filterValues(cache.get(), equalTo(type)).keySet());
}
@@ -955,8 +955,8 @@ public class Registry extends ImmutableObject implements Buildable, UnsafeSerial
"Cannot create registry for TLD that is not a valid, canonical domain name");
// Check the validity of all TimedTransitionProperties to ensure that they have values for
// START_OF_TIME. The setters above have already checked this for new values, but also check
// here to catch cases where we loaded an invalid TimedTransitionProperty from Datastore and
// cloned it into a new builder, to block re-building a Registry in an invalid state.
// here to catch cases where we loaded an invalid TimedTransitionProperty from the database
// and cloned it into a new builder, to block re-building a Registry in an invalid state.
instance.tldStateTransitions.checkValidity();
instance.renewBillingCostTransitions.checkValidity();
instance.eapFeeSchedule.checkValidity();
@@ -106,7 +106,7 @@ public final class ReservedList
}
/**
* A reserved list entry entity, persisted to Datastore, that represents a single label and its
* A reserved list entry entity, persisted to the database, that represents a single label and its
* reservation type.
*/
@javax.persistence.Entity(name = "ReservedEntry")
@@ -25,6 +25,7 @@ import google.registry.monitoring.whitebox.WhiteboxModule;
import google.registry.request.RequestComponentBuilder;
import google.registry.request.RequestModule;
import google.registry.request.RequestScope;
import google.registry.ui.server.console.ConsoleDomainGetAction;
import google.registry.ui.server.registrar.ConsoleOteSetupAction;
import google.registry.ui.server.registrar.ConsoleRegistrarCreatorAction;
import google.registry.ui.server.registrar.ConsoleUiAction;
@@ -61,6 +62,8 @@ interface FrontendRequestComponent {
RegistryLockVerifyAction registryLockVerifyAction();
ConsoleDomainGetAction consoleDomainGetAction();
@Subcomponent.Builder
abstract class Builder implements RequestComponentBuilder<FrontendRequestComponent> {
@Override public abstract Builder requestModule(RequestModule requestModule);
@@ -22,6 +22,7 @@ import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.Expose;
import google.registry.model.EppResource;
import google.registry.model.ImmutableObject;
import google.registry.model.contact.Contact;
@@ -52,7 +53,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
.collect(toImmutableMap(Class::getSimpleName, identity()));
// The primary key for the referenced entity.
Serializable key;
@Expose Serializable key;
Class<? extends T> kind;
@@ -52,9 +52,9 @@ public class CriteriaQueryBuilder<T> {
}
/** Adds a WHERE clause to the query, given the specified operation, field, and value. */
public <V> CriteriaQueryBuilder<T> where(
String fieldName, WhereOperator<V> whereClause, V value) {
Expression<V> expression = root.get(fieldName);
public <U> CriteriaQueryBuilder<T> where(
String fieldName, WhereOperator<U> whereClause, U value) {
Expression<U> expression = root.get(fieldName);
return where(whereClause.predicate(expression, value));
}
@@ -74,7 +74,7 @@ public class CriteriaQueryBuilder<T> {
* Adds a WHERE clause to the query specifying that a collection field must contain a particular
* value.
*/
public <V> CriteriaQueryBuilder<T> whereFieldContains(String fieldName, Object value) {
public CriteriaQueryBuilder<T> whereFieldContains(String fieldName, Object value) {
return where(
jpaTm.getEntityManager().getCriteriaBuilder().isMember(value, root.get(fieldName)));
}
@@ -76,11 +76,6 @@ public interface JpaTransactionManager extends TransactionManager {
*/
Query query(String sqlString);
/**
* Execute the work in a transaction without recording the transaction for replay to datastore.
*/
<T> T transactWithoutBackup(Supplier<T> work);
/** Executes the work in a transaction with no retries and returns the result. */
<T> T transactNoRetry(Supplier<T> work);
@@ -157,11 +157,6 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
return retrier.callWithRetry(() -> transactNoRetry(work), JpaRetries::isFailedTxnRetriable);
}
@Override
public <T> T transactWithoutBackup(Supplier<T> work) {
return transact(work);
}
@Override
public <T> T transactNoRetry(Supplier<T> work) {
if (inTransaction()) {
@@ -16,12 +16,12 @@ package google.registry.persistence.transaction;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import google.registry.persistence.transaction.CriteriaQueryBuilder.WhereOperator;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import javax.persistence.criteria.CriteriaBuilder;
@@ -40,14 +40,13 @@ import javax.persistence.criteria.CriteriaBuilder;
*/
public abstract class QueryComposer<T> {
// The class whose entities we're querying. Note that this limits us to single table queries in
// SQL. In datastore, there's really no other kind of query.
// The class whose entities we're querying.
protected Class<T> entityClass;
// Field to order by, if any. Null if we don't care about order.
@Nullable protected String orderBy;
protected List<WhereClause<?>> predicates = new ArrayList<WhereClause<?>>();
protected List<WhereClause<?>> predicates = new ArrayList<>();
protected QueryComposer(Class<T> entityClass) {
this.entityClass = entityClass;
@@ -61,14 +60,14 @@ public abstract class QueryComposer<T> {
*/
public <U extends Comparable<? super U>> QueryComposer<T> where(
String fieldName, Comparator comparator, U value) {
predicates.add(new WhereClause(fieldName, comparator, value));
predicates.add(new WhereClause<>(fieldName, comparator, value));
return this;
}
/**
* Order the query results by the value of the specified field.
*
* <p>TODO(mmuller): add the ability to do descending sort order.
* <p>TODO: add the ability to do descending sort order.
*/
public QueryComposer<T> orderBy(String fieldName) {
orderBy = fieldName;
@@ -151,52 +150,35 @@ public abstract class QueryComposer<T> {
* "someval")'}.
*/
public enum Comparator {
/**
* Return only records whose field is equal to the value.
*
* <p>Note that the datastore string for this is empty, which is consistent with the way {@code
* filter()} works (it uses an unadorned field name to check for equality).
*/
EQ("", QueryComposer::equal),
/** Return only records whose field is equal to the value. */
EQ(QueryComposer::equal),
/** Return only records whose field is less than the value. */
LT(" <", QueryComposer::lessThan),
LT(QueryComposer::lessThan),
/** Return only records whose field is less than or equal to the value. */
LTE(" <=", QueryComposer::lessThanOrEqualTo),
LTE(QueryComposer::lessThanOrEqualTo),
/** Return only records whose field is greater than or equal to the value. */
GTE(" >=", QueryComposer::greaterThanOrEqualTo),
GTE(QueryComposer::greaterThanOrEqualTo),
/** Return only records whose field is greater than the value. */
GT(" >", QueryComposer::greaterThan),
GT(QueryComposer::greaterThan),
/**
* Return only records whose field matches the pattern.
*
* <p>SQL ONLY.
*/
LIKE(null, QueryComposer::like);
private final String datastoreString;
/** Return only records whose field matches the pattern. */
LIKE(QueryComposer::like);
@SuppressWarnings("ImmutableEnumChecker") // Functions are immutable.
private final Function<CriteriaBuilder, WhereOperator<?>> operatorFactory;
Comparator(
String datastoreString, Function<CriteriaBuilder, WhereOperator<?>> operatorFactory) {
this.datastoreString = datastoreString;
Comparator(Function<CriteriaBuilder, WhereOperator<?>> operatorFactory) {
this.operatorFactory = operatorFactory;
}
public String getDatastoreString() {
return datastoreString;
}
public Function<CriteriaBuilder, WhereOperator<?>> getComparisonFactory() {
return operatorFactory;
}
};
}
protected static class WhereClause<U extends Comparable<? super U>> {
public String fieldName;
@@ -143,8 +143,8 @@ public class RdapJsonFormatter {
*
* <p>Reserved to cases when this object is one of many results of a search query.
*
* <p>We want to minimize the size of the reply, and also minimize the Datastore queries needed
* to generate these replies since we might have a lot of these objects to return.
* <p>We want to minimize the size of the reply, and also minimize the queries needed to
* generate these replies since we might have a lot of these objects to return.
*
* <p>Each object with a SUMMARY type will have a remark with a direct link to itself, which
* will return the FULL result.
@@ -743,16 +743,9 @@ public class RdapJsonFormatter {
// Rdap Response Profile 2.4.5 says the Registrar inside a Domain response MUST include the
// ABUSE contact, but doesn't require any other contact.
//
// In our current Datastore schema, to get the ABUSE contact we must go over all contacts.
// However, there's something to be said about returning smaller JSON
// Write the minimum, meaning only ABUSE for INTERNAL registrars, nothing for SUMMARY and
// everything for FULL.
//
// TODO(b/117242274): Need to decide between 2 options:
// - Write the minimum, meaning only ABUSE for INTERNAL registrars, nothing for SUMMARY (also
// saves resources for the RegistrarContact Datastore query!) and everything for FULL.
// - Write everything for everything.
//
// For now we'll do the first.
if (outputDataType != OutputDataType.SUMMARY) {
ImmutableList<RdapContactEntity> registrarContacts =
registrar.getContacts().stream()
@@ -145,9 +145,8 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
* clauses that make up this SQL query
* @param checkForVisibility true if the results should be checked to make sure they are visible;
* normally this should be equal to the shouldIncludeDeleted setting, but in cases where the
* query could not check deletion status (due to Datastore limitations such as the limit of
* one field queried for inequality, for instance), it may need to be set to true even when
* not including deleted records
* query could not check deletion status, it may need to be set to true even when not
* including deleted records
* @param querySizeLimit the maximum number of items the query is expected to return, usually
* because the limit has been set
* @return an {@link RdapResultSet} object containing the list of resources and an incompleteness
@@ -35,12 +35,12 @@ import org.joda.time.Duration;
* <p>This class implements the <i>Locking Rolling Cursor</i> pattern, which solves the problem of
* how to reliably execute App Engine tasks which can't be made idempotent.
*
* <p>{@link LockHandler} is used to ensure only one task executes at a time for a given
* {@code LockedCursorTask} subclass + TLD combination. This is necessary because App Engine tasks
* might double-execute. Normally tasks solve this by being idempotent, but that's not possible for
* RDE, which writes to a GCS filename with a deterministic name. So Datastore is used to to
* guarantee isolation. If we can't acquire the lock, it means the task is already running, so
* {@link NoContentException} is thrown to cancel the task.
* <p>{@link LockHandler} is used to ensure only one task executes at a time for a given {@code
* LockedCursorTask} subclass + TLD combination. This is necessary because App Engine tasks might
* double-execute. Normally tasks solve this by being idempotent, but that's not possible for RDE,
* which writes to a GCS filename with a deterministic name. So locks are used to guarantee
* isolation. If we can't acquire the lock, it means the task is already running, so {@link
* NoContentException} is thrown to cancel the task.
*
* <p>The specific date for which the deposit is generated depends on the current position of the
* {@link Cursor}. If the cursor is set to tomorrow, we do nothing and return 204 No Content. If the
@@ -59,7 +59,7 @@ class EscrowTaskRunner {
/**
* Performs task logic while the lock is held.
*
* @param watermark the logical time for a point-in-time view of Datastore
* @param watermark the logical time for a point-in-time view of the database.
*/
void runWithLock(DateTime watermark) throws Exception;
}
@@ -48,7 +48,7 @@ import org.joda.time.Duration;
*
* <p>If no deposits have been made so far, then {@code startingPoint} is used as the watermark of
* the next deposit. If that's a day in the future, then escrow won't start until that date. This
* first deposit time will be set to Datastore in a transaction.
* first deposit time will be set to the database in a transaction.
*/
public final class PendingDepositChecker {
@@ -15,10 +15,7 @@
package google.registry.reporting.billing;
import static google.registry.beam.BeamUtils.createJobName;
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_OK;
@@ -32,7 +29,6 @@ import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.model.common.Cursor;
import google.registry.persistence.PersistenceModule;
import google.registry.reporting.ReportingModule;
import google.registry.request.Action;
@@ -44,7 +40,6 @@ import google.registry.util.Clock;
import google.registry.util.CloudTasksUtils;
import java.io.IOException;
import javax.inject.Inject;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.joda.time.YearMonth;
@@ -113,19 +108,6 @@ public class GenerateInvoicesAction implements Runnable {
response.setContentType(MediaType.PLAIN_TEXT_UTF_8);
logger.atInfo().log("Launching invoicing pipeline for %s.", yearMonth);
try {
DateTime currentCursorTime =
tm().transact(
() ->
tm().loadByKeyIfPresent(Cursor.createGlobalVKey(RECURRING_BILLING))
.orElse(Cursor.createGlobal(RECURRING_BILLING, START_OF_TIME))
.getCursorTime());
if (!YearMonth.fromDateFields(currentCursorTime.toDate()).isAfter(yearMonth)) {
throw new IllegalStateException(
"Latest billing events expansion cycle hasn't finished yet, terminating invoicing"
+ " pipeline");
}
LaunchFlexTemplateParameter parameter =
new LaunchFlexTemplateParameter()
.setJobName(createJobName("invoicing", clock))
@@ -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();
}
}
@@ -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 (TokenVerifier.VerificationException 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);
}
}
@@ -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;
}
}
}
@@ -39,7 +39,7 @@ import javax.inject.Inject;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/** Implementation of {@link LockHandler} that uses the datastore lock. */
/** Implementation of {@link LockHandler} that uses the database lock. */
public class LockHandlerImpl implements LockHandler {
private static final long serialVersionUID = 5746905970040002524L;
@@ -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
@@ -38,10 +38,11 @@ public final class LordnTaskUtils {
public static final String QUEUE_SUNRISE = "lordn-sunrise";
public static final String QUEUE_CLAIMS = "lordn-claims";
public static final String COLUMNS_CLAIMS = "roid,domain-name,notice-id,registrar-id,"
+ "registration-datetime,ack-datetime,application-datetime";
public static final String COLUMNS_SUNRISE = "roid,domain-name,SMD-id,registrar-id,"
+ "registration-datetime,application-datetime";
public static final String COLUMNS_CLAIMS =
"roid,domain-name,notice-id,registrar-id,"
+ "registration-datetime,ack-datetime,application-datetime";
public static final String COLUMNS_SUNRISE =
"roid,domain-name,SMD-id,registrar-id," + "registration-datetime,application-datetime";
/** Enqueues a task in the LORDN queue representing a line of CSV for LORDN export. */
public static void enqueueDomainTask(Domain domain) {
@@ -50,20 +51,27 @@ public final class LordnTaskUtils {
// isn't yet populated when this method is called during the resource flow.
String tld = domain.getTld();
if (domain.getLaunchNotice() == null) {
getQueue(QUEUE_SUNRISE).add(TaskOptions.Builder
.withTag(tld)
.method(Method.PULL)
.payload(getCsvLineForSunriseDomain(domain, tm().getTransactionTime())));
getQueue(QUEUE_SUNRISE)
.add(
TaskOptions.Builder.withTag(tld)
.method(Method.PULL)
.payload(getCsvLineForSunriseDomain(domain, tm().getTransactionTime())));
} else {
getQueue(QUEUE_CLAIMS).add(TaskOptions.Builder
.withTag(tld)
.method(Method.PULL)
.payload(getCsvLineForClaimsDomain(domain, tm().getTransactionTime())));
getQueue(QUEUE_CLAIMS)
.add(
TaskOptions.Builder.withTag(tld)
.method(Method.PULL)
.payload(getCsvLineForClaimsDomain(domain, tm().getTransactionTime())));
}
}
/** 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(),
@@ -74,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(),
@@ -95,4 +108,10 @@ public final class LordnTaskUtils {
}
private LordnTaskUtils() {}
public enum LordnPhase {
SUNRISE,
CLAIMS,
NONE
}
}
@@ -15,14 +15,17 @@
package google.registry.tmch;
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
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;
@@ -31,25 +34,31 @@ import com.google.api.client.http.HttpMethods;
import com.google.appengine.api.taskqueue.LeaseOptions;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.TaskHandle;
import com.google.appengine.api.taskqueue.TaskOptions;
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;
import com.google.common.collect.ImmutableMultimap;
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.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;
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.TaskQueueUtils;
import google.registry.util.UrlConnectionException;
import java.io.IOException;
import java.net.HttpURLConnection;
@@ -57,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;
@@ -79,8 +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 BATCH_SIZE = 1000;
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Duration LEASE_PERIOD = Duration.standardHours(1);
@@ -97,28 +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 TaskQueueUtils taskQueueUtils;
@Inject NordnUploadAction() {}
@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() {}
/**
* 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_CLAIMS = "claims";
private static final String PARAM_LORDN_PHASE_SUNRISE =
Ascii.toLowerCase(LordnPhase.SUNRISE.toString());
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());
});
}
}
@@ -127,7 +214,7 @@ public final class NordnUploadAction implements Runnable {
* delimited String.
*/
static String convertTasksToCsv(List<TaskHandle> tasks, DateTime now, String columns) {
// Use a Set for deduping purposes so we can be idempotent in case tasks happened to be
// Use a Set for deduping purposes, so we can be idempotent in case tasks happened to be
// enqueued multiple times for a given domain create.
ImmutableSortedSet.Builder<String> builder =
new ImmutableSortedSet.Builder<>(Ordering.natural());
@@ -152,7 +239,7 @@ public final class NordnUploadAction implements Runnable {
queue.leaseTasks(
LeaseOptions.Builder.withTag(tld)
.leasePeriod(LEASE_PERIOD.getMillis(), TimeUnit.MILLISECONDS)
.countLimit(TaskQueueUtils.getBatchSize())),
.countLimit(BATCH_SIZE)),
TransientFailureException.class,
DeadlineExceededException.class);
if (tasks.isEmpty()) {
@@ -163,9 +250,10 @@ 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.", phase);
checkArgument(
phase.equals(PARAM_LORDN_PHASE_SUNRISE) || phase.equals(PARAM_LORDN_PHASE_CLAIMS),
"Invalid phase specified to NordnUploadAction: %s.",
phase);
DateTime now = clock.nowUtc();
Queue queue =
getQueue(
@@ -177,12 +265,16 @@ 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);
taskQueueUtils.deleteTasks(queue, tasks);
Lists.partition(tasks, BATCH_SIZE)
.forEach(
batch ->
retrier.callWithRetry(
() -> queue.deleteTask(batch), TransientFailureException.class));
}
}
@@ -231,18 +323,22 @@ public final class NordnUploadAction implements Runnable {
actionLogId),
connection);
}
getQueue(NordnVerifyAction.QUEUE).add(makeVerifyTask(new URL(location)));
cloudTasksUtils.enqueue(NordnVerifyAction.QUEUE, makeVerifyTask(new URL(location)));
} catch (IOException e) {
throw new IOException(String.format("Error connecting to MarksDB at URL %s", url), e);
}
}
private TaskOptions makeVerifyTask(URL url) {
private Task makeVerifyTask(URL url) {
// The actionLogId is used to uniquely associate the verify task back to the upload task.
return withUrl(NordnVerifyAction.PATH)
.header(NordnVerifyAction.URL_HEADER, url.toString())
.header(NordnVerifyAction.HEADER_ACTION_LOG_ID, actionLogId)
.param(RequestParameters.PARAM_TLD, tld)
.countdownMillis(VERIFY_DELAY.getMillis());
return cloudTasksUtils.createPostTaskWithDelay(
NordnVerifyAction.PATH,
Service.BACKEND.toString(),
ImmutableMultimap.<String, String>builder()
.put(NordnVerifyAction.NORDN_URL_PARAM, url.toString())
.put(NordnVerifyAction.NORDN_LOG_ID_PARAM, actionLogId)
.put(RequestParameters.PARAM_TLD, tld)
.build(),
Duration.millis(VERIFY_DELAY.getMillis()));
}
}
@@ -23,7 +23,6 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.ByteSource;
import google.registry.request.Action;
import google.registry.request.Header;
import google.registry.request.HttpException.ConflictException;
import google.registry.request.Parameter;
import google.registry.request.RequestParameters;
@@ -60,8 +59,8 @@ public final class NordnVerifyAction implements Runnable {
static final String PATH = "/_dr/task/nordnVerify";
static final String QUEUE = "marksdb";
static final String URL_HEADER = "X-DomainRegistry-Nordn-Url";
static final String HEADER_ACTION_LOG_ID = "X-DomainRegistry-ActionLogId";
static final String NORDN_URL_PARAM = "nordnUrl";
static final String NORDN_LOG_ID_PARAM = "nordnLogId";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -69,10 +68,20 @@ public final class NordnVerifyAction implements Runnable {
@Inject Response response;
@Inject UrlConnectionService urlConnectionService;
@Inject @Header(URL_HEADER) URL url;
@Inject @Header(HEADER_ACTION_LOG_ID) String actionLogId;
@Inject @Parameter(RequestParameters.PARAM_TLD) String tld;
@Inject NordnVerifyAction() {}
@Inject
@Parameter(NORDN_URL_PARAM)
URL url;
@Inject
@Parameter(NORDN_LOG_ID_PARAM)
String actionLogId;
@Inject
@Parameter(RequestParameters.PARAM_TLD)
String tld;
@Inject
NordnVerifyAction() {}
@Override
public void run() {
@@ -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);
}
@@ -27,8 +27,10 @@ import org.bouncycastle.openpgp.bc.BcPGPPublicKeyRing;
/** Helper class for common data loaded from the jar and SQL at runtime. */
public final class TmchData {
private static final String BEGIN_ENCODED_SMD = "-----BEGIN ENCODED SMD-----";
private static final String END_ENCODED_SMD = "-----END ENCODED SMD-----";
static final String BEGIN_ENCODED_SMD = "-----BEGIN ENCODED SMD-----";
static final String END_ENCODED_SMD = "-----END ENCODED SMD-----";
private TmchData() {}
static PGPPublicKey loadPublicKey(ByteSource pgpPublicKeyFile) {
try (InputStream input = pgpPublicKeyFile.openStream();

Some files were not shown because too many files have changed in this diff Show More