1
0
mirror of https://github.com/google/nomulus synced 2026-05-19 22:31:47 +00:00

Compare commits

...

61 Commits

Author SHA1 Message Date
Rachel Guan
3beb207fcc Add email set up for sending expiring certificate notification emails (#1248)
* Add email set up for sending expiring certificate notification emails
2021-07-21 15:47:27 -04:00
gbrodman
8cf88b7e18 Avoid unnecessary tm() calls without ofy init in Spec11PipelineTest (#1250)
* Avoid unnecessary tm() calls without ofy init in Spec11PipelineTest
2021-07-20 15:10:50 -04:00
gbrodman
6ec2e9501d Fix flaky test issues caused by lack of ofy init (#1246) 2021-07-20 13:14:41 -04:00
sarahcaseybot
6849bf6914 Use less strict isolation level in Spec11 pipeline (#1244) 2021-07-16 15:46:34 -04:00
gbrodman
34f3823960 Fix hanging threads in GcsDiffFileLister (#1243)
* Fix hanging threads in GcsDiffFileLister

Basically, whenever we request threads using the request thread factory,
we must be on the request thread itself. Dagger doesn't guarantee this
for us if we provide the ExecutorService directly in the action (or in
the GcsDiffFileLister), but we can gurantee that we're on the request
thread itself by simply injecting a Lazy, so that the executor is
instantiated inside the request itself.

In addition, add a timeout on the futures just in case.
2021-07-16 14:13:20 -04:00
gbrodman
bb5d2dcf0a Use the DatabaseMigrationSchedule to determine which TM to use (#1233)
* Use the DatabaseMigrationSchedule to determine which TM to use

We still allow the "manual" specification of a particular transaction
manager, most useful in @DualDatabaseTest classes. If that isn't
specified, we examine the migration schedule to see which to return.

Notes:
- This requires that any test that sets the migration schedule clean up
after itself so that it won't affect future test runs of other classes
(because the migration schedule cache is static)
- One alternative would, instead of having a "test override" for the
transaction manager, be to examine the registry environment and only
override the transaction manager in the UNIT_TEST environment. This
doesn't work because there are many instances in which tests simulate
non-test environment.
2021-07-14 13:05:01 -04:00
sarahcaseybot
6ce0211537 Remove key references from BaseDomainLabelList (#1239) 2021-07-13 16:49:34 -04:00
Lai Jiang
676616a172 Remove the use of GCS APIs provided from GAE SDK (#1228)
The API provided by the GAE SDK will not be available outside GAE
runtime. This presents a problem when we migrate off of GAE. More
pressingly, the RDE pipeline migration to Beam requires that we write to
GCS on GCE. Previously we were able to sidestep the issue by delegating
the writes to FileIO provided by Beam, which knows how to write to GCS.
However the RDE pipeline cannot use FileIO directly as it needs to write
to multiple files in one go and explicit use of GCS API is needed.

An unfortunate side effect of the API migration is that the new testing
library contains a bug which makes serializing GcsUtils impossible. It
is fixed upstream but not released yet. The fix has been backported for
the time being.

<!-- 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/1228)
<!-- Reviewable:end -->
2021-07-13 14:52:37 -04:00
Weimin Yu
62c556cebf Restore commit logs from other project (#1236)
* Restore commit logs from other project

Allow non-production projects to restore commit logs from another
project. This feature can be used to duplicate a realistic testing
environment.

An optional parameter is added that can override the default commit log
location.

Tested successfully in QA.
2021-07-12 16:56:47 -04:00
Ben McIlwain
535f84a912 Add better logging/error messages for Cloud DNS failures (#1237)
* Add better logging/error messages for Cloud DNS failures
2021-07-09 17:04:57 -04:00
sarahcaseybot
d283cf1c90 Remove old DomainList fields from Registry (#1231)
* Remove old DomainList fields from Registry

I also resaved all Registry objects in sandbox and production to make sure that the new field is populated on all entity objects.

* small fixes

* Some more small fixes

* Delete commented out code

* Remove existence check in tests
2021-07-08 17:19:11 -04:00
Rachel Guan
f5d344d5c9 Add cc support to email service (#1230)
* Add cc support to email service
2021-07-08 12:03:03 -04:00
Weimin Yu
61d029d955 Ensure VKey is actually serializable (#1235)
* Ensure VKey is actually serializable

Tighten field type so that non-serializable object cannot be set as
sqlKey.

This would make it easier to make EppResource entities Serializable in
the future.
2021-07-08 10:54:22 -04:00
Lai Jiang
2195ba90fa Add a method to set a "not in" WHERE clause in CriteriaQueryBuilder (#1225)
<!-- 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/1225)
<!-- Reviewable:end -->
2021-07-07 15:49:29 -04:00
gbrodman
e5b9ff1498 Add a dry-run option to commit-log-replay action and use it in Sandbox (#1234) 2021-07-03 11:18:00 -04:00
Ben McIlwain
3f9fec98d5 Add more logging to replay commit logs action (#1232) 2021-07-02 18:06:04 -04:00
Ben McIlwain
4e30d020ca Set payload response in happy path of ReplayCommitLogsToSqlAction (#1229)
* Set payload response in happy path of ReplayCommitLogsToSqlAction

I suspect this may be the reason the logs are missing on the happy path (when it
runs successfully), but are visible on the exception paths (which do set the
payload response). I don't think App Engine likes it when a Web request
terminates without a response.

This also adds more logging and error handling.
2021-07-01 18:21:17 -04:00
Lai Jiang
047444831b Add a Beam pipeline to generate RDE deposit (part 1) (#1219)
This is the first part of the RdeStagingAction SQL migration where the
mapper logic is implemented in Beam.

A few helper methods are added to convert the DomainContent, HostBase
and ContactBase to their respective terminal child classes. This is
necessary and possible because the child classes do not have extra
fields and the base classes exist only to be embedded to other entities
(such as the various HistoryEntry entities). The conversion is necessary
because most of our code expects the terminal classes, such as the
RdeMarshaller's various marshallXXX() methods. The alternative would be
to change all the call sites, which seems to be much more disruptive.

Unfortunately there is is no good way to do this conversion than just
creating a builder and setting every fields there is.

<!-- 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/1219)
<!-- Reviewable:end -->
2021-06-30 13:54:24 -04:00
Weimin Yu
7adcbee5ad Retry flaky tests for ReplicateToDatastoreAction (#1226)
* Retry flaky tests for ReplicateToDatastoreAction

The occassional failures seem to be caused by the test Datastore.
2021-06-29 17:12:02 -04:00
Michael Muller
78a750b7e1 Support testing SQL -> DS replication in ReplayExt (#1216)
* Support testing SQL -> DS replication in ReplayExt

Support testing of Postgres -> Datastore replication in the ReplayExtension
when running in SQL mode in a DualDatabaseTest.

This is currently only enabled for one test (HostInfoFlowTest) since this form
of replication is likely to be problematic in many cases.

As part of this change:

- Add a thread-local flag so that we don't attempt to do certain data
  transformations when serializing entities for storage in a Transaction
  record. (These typically need to be called in a datastore transaction).
- Replace tm() in datastore translators with ofyTm() (these should only be
  called from within an ofy transaction) and also in the replay system itself.
- Add a transactWithoutBackup() method for use within the replay itself.
- Prevent replication of entities that are not intended to be replicated.
- Make some of the ReplicateToDatastoreAction methods public so we can invoke
  them from ReplayExtension.
- Change the way that the test type is stored in the extension context in a
  DualDatabaseTest so that we can check for it from the ReplayExtension.

* Limit number of tests and show output

Trying to debug why these are failing in kokoro.

* Move HostInfoFlowTest to fragile for now

The test now manipulates a globel variable that causes problems for other
tests.  There's likely a better fix for this, but for purposes of this PR we
can just move it to "fragile."

* Fix a few more problems

-   "replay" flag should have been initialized to false -- as it stands,
    replay wasn't happening.
-   disable "always save with backup" in the datastore helper, we were
    apparently getting some unwanted commit log entries that were causing
    timestamp inversions in other tests.  Also clear out the replay queue
    just for good hygiene.
-   Check for a null replicator in replayToOfy before proceeding.
-   Use a local inOfyContext flag to track whether we're in ofy context, as
    the tm() function is less reliable in dual-database tests.
2021-06-29 10:00:39 -04:00
Ben McIlwain
2e8a1c422d Set HistoryEntry modification time in FlowModule (#1222)
* Set HistoryEntry modification time in FlowModule

Rather than having to set it individually to now (the current transaction time)
in every transactional flow, just do it once at the beginning when the
HistoryEntry.Builder is first being provided. This is also safer, as just doing
it in one place gives us stronger guarantees that it always corresponds to the
execution time of the flow, rather than leaving the potential open that in one
flow it's unintentionally set to the wrong thing.
2021-06-29 09:05:12 -04:00
gbrodman
0e5605b175 Set a 5min time limit on the SQL replay action (#1224)
This means we avoid GAE request timeouts and can get progress logs more
quickly (logs weren't showing up on GAE in Sandbox).
2021-06-28 17:01:16 -04:00
Ben McIlwain
a10b5d8b30 Rename a few soy files for consistency (#1223)
* Rename a few soy files for consistency

This prefers the ResourceAction.soy naming convention for .soy files that
contain EPP XMLs so that they match the name of the corresponding EPP flow. E.g.
DomainDelete.soy now matches DomainDeleteFlow.java
2021-06-28 12:00:08 -04:00
Ben McIlwain
b7ce08dfdc Fix BigDecimal precision of PremiumList.getLabelsToPrices() (#1221)
* Fix BigDecimal precision of PremiumList.getLabelsToPrices()

Different currencies have different numbers of decimal places (e.g. USD has 2,
JPY has 0, and some even have 3). Thus, when loading the contents of a premium
list, we need to set the precision correctly on all of the BigDecimal prices.

This issue was introduced as part of the Registry 3.0 database migration when we
changed each PremiumEntry to being a Money to a BigDecimal (to remove the
redundancy of storing the same currency value over and over).
2021-06-25 19:10:21 -04:00
Lai Jiang
a3e8bf219f Remove some unnecessary Ofy key creation (#1212) 2021-06-24 17:35:39 -04:00
gbrodman
546eba68bd Add SQL functionality to DeleteLoadTestDataAction (#1211)
* Add SQL functionality to DeleteLoadTestDataAction

This isn't directly meant to be run in production so some of the rough
edges (doesn't delete domains, can't delete contacts that are referenced
by an existing domain) are fine. We can handle those in
DeleteProberTestAction when we do the more comprehensive deletions.
2021-06-23 15:39:22 -04:00
Weimin Yu
81fcdbdcea Make SQL queries return scrollable results (#1214)
* Make SQL queries return scrollable results

With Postgresql, we must override the default fetchSize (0) to enable
scrollable result sets. Previously we only did this in QueryComposer.

In this change we enable scrollable results for all queries by default.
We also provide a helper function
(JpaTransactionManager.setQueryFetchSize) that can override the default.
2021-06-22 22:13:57 -04:00
Weimin Yu
2b91e3bb89 Fix appId during cross-project commitlog imports (#1213)
* Fix appId during cross-project commitlog imports

When importing commit logs from another project, we must override the
appId in every entity key instances.

The fixEntity method in the EntityImports class is a straightforward
translation of the python function of the same name used by the
storage team.
2021-06-22 15:59:58 -04:00
Lai Jiang
ce03556683 Fix a GCB job description (#1215)
<!-- 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/1215)
<!-- Reviewable:end -->
2021-06-22 13:51:26 -04:00
Lai Jiang
967304588b Make RegistryJpaIO use CriteriaQuery intead of QueryComposer (#1209)
QueryComposer could be used when the transaction manager is not
determined (i. e. it supports both ofy and sql), but this also imposes
limits on what you can do with it. For example it does not support IN
operator in the where clause.

Since QueryComposer itself creates a CriteriaQuery for JPA TM it make
sense to have RegistryJpaIO take a CriteriaQuery directly as it only
uses JPA.

Also add some more helper methods to use native queries and typed
queires, and fix some generic type warnings.

<!-- 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/1209)
<!-- Reviewable:end -->
2021-06-18 10:29:00 -04:00
sarahcaseybot
a2754a0eff Add new domain list fields to Registry objects (#1208)
* Add domain list name fields to Registry objects

* Add some comments

* Added scrap command

* Fix typo

* capitalize TLD
2021-06-16 15:13:46 -04:00
Michael Muller
276bbc09c2 Add RDE Staging to QA crontab. (#1210)
* Add RDE Staging to QA crontab.
2021-06-15 15:02:47 -04:00
Lai Jiang
fd461a78e7 Unwrap the return value of loadAtPointInTime (#1205)
In SQL we do not need to wrap it in a Result. Unfortunately we cannot
overload a function based on its return value so we renamed the existing
one and created a new one with the old name that returns the resource
directly. Once we no longer have use of Datastore we can delete the now
renamed function that returns a Result<? extends EppResource>

<!-- 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/1205)
<!-- Reviewable:end -->
2021-06-14 11:55:24 -04:00
gbrodman
0374ad60d8 Add ReplayCommitLogsToSqlAction to backend routing (#1203)
Necessary so that we can actually call it from the cron job
2021-06-14 09:59:06 -04:00
sarahcaseybot
fcc027e0c8 Add Cloud SQL read to Spec11Pipeline (#1173)
* Add Cloud SQL read to Spec11Pipeline

* Add database option

* Add database parameter

* Add a test of the full pipeline

* Use DatabaseHelper in tests

* restore the original tm

* More test fixes
2021-06-11 14:25:20 -04:00
Weimin Yu
c3a4887845 Fix timestamp inversion error in a test (#1207)
* Fix timestamp inversion error in a test
2021-06-11 11:05:10 -04:00
Ben McIlwain
a0b6437f4c Add reason/registrar request options when creating/updating domains (#1202)
* Add reason/registrar_request options when creating/updating domains
2021-06-11 10:50:32 -04:00
Lai Jiang
a7210a26b4 Make RefreshDnsForAllDomains SQL-aware (#1197)
Also marks a few mapreduce actions as @Deprecated as they are no longer
needed in SQL.

<!-- 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/1197)
<!-- Reviewable:end -->
2021-06-10 21:09:19 -04:00
Lai Jiang
c7096a1b71 Fix a flaky test (#1204)
In testSuccess_expandSingleEvent_notIdempotentforDifferentRecurring(),
two Recurring entities are created with the only difference being their IDs. If
we don't order the Recurrings by ID when loading them there is no guarantee
which one is expanded first. In this test the expected OneTime entities are
created with the assumption that the first loaded DomainHistory (parent of a
OneTime) corresponds to the expanding the Recurring with the smaller ID (2L).
Since the DomainHistory entities are loaded in order of IDs, and the IDs are
created monotonically in time in tests, we need to load the Recurrings in
order of their IDs to ensure that the first DomainHistory is the result of
expanding the Recurring with ID of 2L. This should impose minimum performance
penalty as we are ordering by the primary key.

<!-- 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/1204)
<!-- Reviewable:end -->
2021-06-10 14:06:05 -04:00
gbrodman
30634ff404 Convert EppResourceUtils::loadAtPointInTime to SQL+DS (#1194)
* Convert EppResourceUtils::loadAtPointInTime to SQL+DS

This required the following changes:
- The branching / conversion logic itself, where we load the most recent
history object for the resource in question (or just return the resource
itself)
- For simplicity's sake, adding a method in the *History objects that
returns the generic resource -- this means that it can be called when we
don't know or care which subclass it is.
- Populating the domain's dsData and gracePeriods fields from the
DomainHistory fields, and adding factories in the relevant classes to
allow us to do the conversions nicely (the history classes are almost
the same as the regular ones, but not quite).
- Change the tests to use the clocks properly and to allow comparison of
e.g. DomainContent to DomainBase. The objects aren't the same (one is a
superclass of the other) but the fields are.

Note as well a slight behavioral change: commit logs only allow us
24-hour granularity, so two updates in the same day mean that the
earlier update is ignored and inaccessible. This is not the case for
*History objects in SQL; all versions are accessible.
2021-06-10 12:25:06 -04:00
Lai Jiang
4f71d780ab Make ExportDomainListsAction SQL-aware (#1195)
<!-- 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/1195)
<!-- Reviewable:end -->
2021-06-10 12:03:17 -04:00
Michael Muller
14ad56a392 Fix Datastore "count" queries (#1201)
* Fix Datastore "count" queries

The objectify "count()" method doesn't work for result sets larger than 1000
elements, use the original trick from "count domains" that fetches the keys
and counts them.

* Added an SO link
2021-06-08 15:23:25 -04:00
gbrodman
a1b56b0521 Convert remaining ofy() calls to auditedOfy() (#1200)
* Convert remaining ofy() calls to auditedOfy()
2021-06-08 13:52:13 -04:00
gbrodman
3f41f7f444 Start the DS->SQL replay cron job in non-prod environments (#1199)
* Start the DS->SQL replay in non-prod environments

This should be a no-op since we haven't enabled it but this means that
when we set the schedule, we'll start replaying
2021-06-08 11:35:47 -04:00
gbrodman
4f6bcea63f Fix a test flake in SetDatabaseMigrationScheduleCommandTest (#1198)
* Fix a test flake in SetDatabaseMigrationScheduleCommandTest

The cache is static so some odd state may stick around between tests --
we should clear it
2021-06-08 11:35:29 -04:00
Lai Jiang
bd0ef626a1 Fix a few test annotations (#1196) 2021-06-08 00:40:58 -04:00
Lai Jiang
68304133c4 Make RefreshDnsOnHostRenameAction SQL-aware (#1190)
<!-- 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/1190)
<!-- Reviewable:end -->
2021-06-07 10:24:49 -04:00
Weimin Yu
16392c3808 Fix access to a nullable field in HistoryEntry (#1193)
* Fix access to a nullable field in HistoryEntry
2021-06-04 16:30:25 -04:00
gbrodman
5f479488fa Use DB migration state to determine running async replay SQL->DS (#1191)
* Use DB migration state to determine running async replay SQL->DS

The SQL->DS replay likely could use more work (locking, returning the
right codes, things like that) but that's outside the scope of this PR.
2021-06-04 16:18:25 -04:00
Michael Muller
886a970ed6 Use detaching queries for all criteria queries (#1192)
* Make all criteria queries use jpaTm().query()

This causes all criteria queries to detach-on-load.

* Detach results of criteria queries

Wrap the criteria queries in DetachingTypedQuery now that the latter is
merged.
2021-06-04 14:37:53 -04:00
Michael Muller
d7f7568761 Fix copy causing premature hash calculation (#1189)
* Fix copy causing premature hash calculation

The creation of a builder to set the DomainContent repo id in DomainHistory
triggers an equality check which causes the hash code of an associated
transfer data object to be calculated prematurely, before the Ofy keys are
reconstituted.  Replace this with a simple setter, which is acceptible in this
case because the object is being loaded and is considered to be not fully
constructed yet.

* Do setRepoId() in Contact and Host history

Not essential for these as far as we know, but it's safer and more consistent.

* Fixed typos
2021-06-04 11:38:42 -04:00
gbrodman
2017930a8f Add commands to set and check the database migration state (#1174) 2021-06-04 09:57:08 -04:00
gbrodman
ed07fc8181 Use DB migration state to determine running async replay DS->SQL (#1175)
* Use DB migration state to determine running async replay DS->SQL
2021-06-03 11:43:26 -04:00
Lai Jiang
aa2898ebfc Make ExpandRecurringBillingEventAction SQL-aware (#1181)
There is some complication regarding how the
CancellationMatchingBillingEvent of the generated OneTime can be
reconstructed when loading from SQL. I decided to only address it in
testing as there is no real value to fully reconstruct this VKey in
production where we are either in SQL or Ofy mode, both never in both.
Therefore the VKey in a particular mode only needs to contain the
corresponding key in order to function.

<!-- 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/1181)
<!-- Reviewable:end -->
2021-06-03 10:21:16 -04:00
gbrodman
586189d7ee Use a TimedTransitionProperty for the DB migration schedule (#1186)
This includes the following changes:
- Convert the single-valued database migration state to a timed
transition property, meaning that we can switch all instances over at
the same time and schedule it in advance
- Use a "cache" (technically an expiring memoized supplier) when
retrieving the database migration state value
- Delete the old DatabaseTransitionSchedule because it is no longer
necessary. We took the idea from that and used it for the new
DatabaseMigrationStateSchedule, though we cannot reuse the entity itself
because the structure is fundamentally different.
- Removed references to the DatabaseTransitionSchedule, mainly in the
getter/setter commands+tests and a few odd references elsewhere.
2021-06-02 14:06:28 -04:00
Lai Jiang
275f364dcb Handle cases where periodYears is NULL in a OneTime (#1187)
There are cases where periodYears is not set when creating a OneTime
billing event, for example when performing a registry lock (default cost = $0)
or when performing a server status update, such as applying the
serverUpdateProhibited status (default cost = $20). This is not currently
handled currently in the billing pipeline because the parseFromRecord
method checks for nullness for all fields. Even if it does not validate
the fields, the null periodYears will still cause problem when the
billing event is converted to CSV files.

This PR alters the BigQuery SQL file to convert a NULL to 0 when
creating the BillingEvent in the invoicing pipeline. It also sets the EndDate
in the invoice CSV to an empty string when periodYears is 0. Note that when the
cost is also 0, the billing event is filtered out in the invoice CSV so only
the non-free OneTime with null periodYear will have an impact on the output.
For detailed reports all billing events are included and the zero
periodYears is printed as is.

Setting the EndDate to empty is the correct behavior per
go/manual-integration-csv#end-date.
2021-06-02 11:52:47 -04:00
Weimin Yu
66867e4397 Use SecretManager for nomulus-tool-cloudbuild cred (#1188)
* Use SecretManager for nomulus-tool-cloudbuild cred

Store cloudbuild's nomulus-tool credential in SecretManager and make the
deployment pipeline load it from the SecretManager.

The tool-credential.json.enc file in the
gs://domain-registry-dev-deploy/secrets folder is no longer needed.
2021-06-02 09:32:57 -04:00
Weimin Yu
3fa56dec45 Make keyring use SecretManager as sole storage (#1185)
* Make keyring use SecretManager as sole storage

The Keyring will only use the SecretManager as storage. Accesses to the
Datastore are removed.

Also consolidated KmsKeyringTest into KmsKeyingUpdaterTest. The latter
is left with its original name to facilitate code reviews. It will be
renamed in planned cleanups.

Additional cleanup is left for a future PR. These include:

- Remove KmsConnection and its associated injection modules

- Remove KmsSecretRevision from SQL schema and code

- Rename relevant files to more appropriate names.
2021-06-01 15:28:22 -04:00
Michael Muller
92f5f8989b Detach entities loaded by loadSingleton() (#1184)
* Detach entities loaded by loadSingleton()

* Reformatted
2021-06-01 14:22:57 -04:00
Michael Muller
810adf0158 Detach result objects obtained through jpaTm().query() (#1183)
* Added TransformingTypedQuery class

Added class to wrap TypedQuery so that we can detach all objects on load.

* Don't detach non-entity results; complete tests

* Changes for review

* Make non-static and call detach directly
2021-06-01 14:20:04 -04:00
gbrodman
f6004181f8 Convert DeleteExpiredDomainsAction to QueryComposer (#1180)
I think this one needed to wait until the detach-on-load PR went in, but
now we should be all set.
2021-06-01 13:32:25 -04:00
402 changed files with 12280 additions and 8706 deletions

View File

@@ -24,7 +24,7 @@ com.google.common.html.types:types:1.0.6
com.google.errorprone:error_prone_annotations:2.5.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0
@@ -53,7 +53,7 @@ org.apache.commons:commons-text:1.6
org.apache.httpcomponents:httpclient:4.5.13
org.apache.httpcomponents:httpcore:4.4.14
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0
org.json:json:20160212
org.ow2.asm:asm-analysis:7.0
org.ow2.asm:asm-commons:7.0

View File

@@ -24,7 +24,7 @@ com.google.common.html.types:types:1.0.6
com.google.errorprone:error_prone_annotations:2.5.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0
@@ -53,7 +53,7 @@ org.apache.commons:commons-text:1.6
org.apache.httpcomponents:httpclient:4.5.13
org.apache.httpcomponents:httpcore:4.4.14
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0
org.json:json:20160212
org.ow2.asm:asm-analysis:7.0
org.ow2.asm:asm-commons:7.0

View File

@@ -24,7 +24,7 @@ com.google.common.html.types:types:1.0.6
com.google.errorprone:error_prone_annotations:2.5.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0
@@ -53,7 +53,7 @@ org.apache.commons:commons-text:1.6
org.apache.httpcomponents:httpclient:4.5.13
org.apache.httpcomponents:httpcore:4.4.14
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0
org.json:json:20160212
org.ow2.asm:asm-analysis:7.0
org.ow2.asm:asm-commons:7.0

View File

@@ -24,7 +24,7 @@ com.google.common.html.types:types:1.0.6
com.google.errorprone:error_prone_annotations:2.5.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0
@@ -53,7 +53,7 @@ org.apache.commons:commons-text:1.6
org.apache.httpcomponents:httpclient:4.5.13
org.apache.httpcomponents:httpcore:4.4.14
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0
org.json:json:20160212
org.ow2.asm:asm-analysis:7.0
org.ow2.asm:asm-commons:7.0

View File

@@ -24,7 +24,7 @@ com.google.common.html.types:types:1.0.6
com.google.errorprone:error_prone_annotations:2.5.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0
@@ -53,7 +53,7 @@ org.apache.commons:commons-text:1.6
org.apache.httpcomponents:httpclient:4.5.13
org.apache.httpcomponents:httpcore:4.4.14
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0
org.json:json:20160212
org.ow2.asm:asm-analysis:7.0
org.ow2.asm:asm-commons:7.0

View File

@@ -24,7 +24,7 @@ com.google.common.html.types:types:1.0.6
com.google.errorprone:error_prone_annotations:2.5.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0

View File

@@ -24,7 +24,7 @@ com.google.common.html.types:types:1.0.6
com.google.errorprone:error_prone_annotations:2.5.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0

View File

@@ -24,7 +24,7 @@ com.google.common.html.types:types:1.0.6
com.google.errorprone:error_prone_annotations:2.5.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0

View File

@@ -24,7 +24,7 @@ com.google.common.html.types:types:1.0.6
com.google.errorprone:error_prone_annotations:2.5.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0

View File

@@ -2,11 +2,11 @@
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_annotations:2.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
javax.inject:javax.inject:1
joda-time:joda-time:2.9.2
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0

View File

@@ -2,11 +2,11 @@
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_annotations:2.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
javax.inject:javax.inject:1
joda-time:joda-time:2.9.2
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0

View File

@@ -2,11 +2,11 @@
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_annotations:2.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
javax.inject:javax.inject:1
joda-time:joda-time:2.9.2
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0

View File

@@ -2,11 +2,11 @@
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_annotations:2.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
javax.inject:javax.inject:1
joda-time:joda-time:2.9.2
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0

View File

@@ -2,11 +2,11 @@
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_annotations:2.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
javax.inject:javax.inject:1
joda-time:joda-time:2.9.2
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0

View File

@@ -2,11 +2,11 @@
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_annotations:2.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
javax.inject:javax.inject:1
joda-time:joda-time:2.9.2
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0

View File

@@ -6,7 +6,7 @@ com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.5.1
com.google.flogger:flogger:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.1.2

View File

@@ -6,7 +6,7 @@ com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.5.1
com.google.flogger:flogger:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.1.2

View File

@@ -7,7 +7,7 @@ com.google.errorprone:error_prone_annotations:2.5.1
com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.1.2

View File

@@ -7,7 +7,7 @@ com.google.errorprone:error_prone_annotations:2.5.1
com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.1.2

View File

@@ -6,7 +6,7 @@ com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.5.1
com.google.flogger:flogger:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.1.2

View File

@@ -6,7 +6,7 @@ com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.5.1
com.google.flogger:flogger:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.1.2

View File

@@ -7,7 +7,7 @@ com.google.errorprone:error_prone_annotations:2.5.1
com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.1.2

View File

@@ -7,7 +7,7 @@ com.google.errorprone:error_prone_annotations:2.5.1
com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.1.2

View File

@@ -79,8 +79,8 @@ PRESUBMITS = {
r".*Copyright 20\d{2} The Nomulus Authors\. All Rights Reserved\.",
("java", "js", "soy", "sql", "py", "sh", "gradle"), {
".git", "/build/", "/generated/", "/generated_tests/",
"node_modules/", "JUnitBackports.java", "registrar_bin.",
"registrar_dbg.", "google-java-format-diff.py",
"node_modules/", "LocalStorageHelper.java", "FakeStorageRpc.java",
"registrar_bin.", "registrar_dbg.", "google-java-format-diff.py",
"nomulus.golden.sql", "soyutils_usegoog.js", "javascript/checks.js"
}, REQUIRED):
"File did not include the license header.",
@@ -202,6 +202,8 @@ PRESUBMITS = {
"java",
# ActivityReportingQueryBuilder deals with Dremel queries
{"src/test", "ActivityReportingQueryBuilder.java",
# This class contains helper method to make queries in Beam.
"RegistryJpaIO.java",
# TODO(b/179158393): Remove everything below, which should be done
# using Criteria
"ForeignKeyIndex.java",

View File

@@ -79,6 +79,9 @@ def fragileTestPatterns = [
// Changes cache timeouts and for some reason appears to have contention
// with other tests.
"google/registry/whois/WhoisCommandFactoryTest.*",
// Currently changes a global configuration parameter that for some reason
// results in timestamp inversions for other tests. TODO(mmuller): fix.
"google/registry/flows/host/HostInfoFlowTest.*",
] + dockerIncompatibleTestPatterns
sourceSets {
@@ -194,6 +197,7 @@ dependencies {
compile deps['com.google.apis:google-api-services-groupssettings']
compile deps['com.google.apis:google-api-services-monitoring']
compile deps['com.google.apis:google-api-services-sheets']
compile deps['com.google.apis:google-api-services-storage']
testCompile deps['com.google.appengine:appengine-api-stubs']
compile deps['com.google.appengine.tools:appengine-gcs-client']
compile deps['com.google.appengine.tools:appengine-mapreduce']
@@ -218,6 +222,8 @@ dependencies {
gradleLint.ignore('unused-dependency') {
compile deps['com.google.gwt:gwt-user']
}
compile deps['com.google.cloud:google-cloud-core']
compile deps['com.google.cloud:google-cloud-storage']
compile deps['com.google.http-client:google-http-client']
compile deps['com.google.http-client:google-http-client-appengine']
compile deps['com.google.http-client:google-http-client-jackson2']
@@ -312,6 +318,7 @@ dependencies {
annotationProcessor project(':processor')
testAnnotationProcessor project(':processor')
testCompile deps['com.google.cloud:google-cloud-nio']
testCompile deps['com.google.appengine:appengine-testing']
testCompile deps['com.google.guava:guava-testlib']
testCompile deps['com.google.monitoring-client:contrib']
@@ -777,6 +784,10 @@ if (environment in ['alpha', 'crash']) {
mainClass: 'google.registry.beam.invoicing.InvoicingPipeline',
metaData: 'google/registry/beam/invoicing_pipeline_metadata.json'
],
[
mainClass: 'google.registry.beam.rde.RdePipeline',
metaData: 'google/registry/beam/rde_pipeline_metadata.json'
],
]
project.tasks.create("stage_beam_pipelines") {
doLast {

View File

@@ -14,14 +14,14 @@ com.google.dagger:dagger-producers:2.33
com.google.dagger:dagger-spi:2.33
com.google.dagger:dagger:2.33
com.google.errorprone:error_prone_annotation:2.3.4
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_annotations:2.5.1
com.google.errorprone:error_prone_check_api:2.3.4
com.google.errorprone:error_prone_core:2.3.4
com.google.errorprone:error_prone_type_annotations:2.3.4
com.google.errorprone:javac-shaded:9-dev-r4023-3
com.google.googlejavaformat:google-java-format:1.5
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.protobuf:protobuf-java:3.4.0
@@ -32,7 +32,7 @@ javax.inject:javax.inject:1
javax.persistence:javax.persistence-api:2.2
net.ltgt.gradle.incap:incap:0.2
org.checkerframework:checker-compat-qual:2.5.3
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0
org.checkerframework:dataflow:3.0.0
org.checkerframework:javacutil:3.0.0
org.jetbrains.kotlin:kotlin-stdlib-common:1.4.20

View File

@@ -55,10 +55,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -76,7 +76,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -97,12 +97,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -113,7 +114,7 @@ com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -133,8 +134,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -221,7 +222,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.20

View File

@@ -54,10 +54,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -75,7 +75,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -96,12 +96,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -111,7 +112,7 @@ com.google.escapevelocity:escapevelocity:0.9.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -131,8 +132,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.14.0
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -215,7 +216,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.conscrypt:conscrypt-openjdk-uber:2.5.1

View File

@@ -59,10 +59,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -80,7 +80,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -102,12 +102,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -118,7 +119,7 @@ com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -138,8 +139,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -232,7 +233,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.20

View File

@@ -59,10 +59,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -80,7 +80,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -102,12 +102,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -118,7 +119,7 @@ com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -138,8 +139,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -231,7 +232,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.20

View File

@@ -55,10 +55,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -76,7 +76,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -97,12 +97,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -113,7 +114,7 @@ com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -133,8 +134,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -221,7 +222,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.20

View File

@@ -54,10 +54,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -75,7 +75,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -96,12 +96,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -111,7 +112,7 @@ com.google.escapevelocity:escapevelocity:0.9.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -131,8 +132,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.14.0
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -216,7 +217,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.conscrypt:conscrypt-openjdk-uber:2.5.1

View File

@@ -59,10 +59,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -80,7 +80,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -101,12 +101,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -117,7 +118,7 @@ com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -137,8 +138,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -231,7 +232,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.20

View File

@@ -59,10 +59,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -80,7 +80,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -101,12 +101,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -117,7 +118,7 @@ com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -137,8 +138,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -231,7 +232,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.20

View File

@@ -59,10 +59,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -80,7 +80,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -101,12 +101,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -117,7 +118,7 @@ com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -137,8 +138,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -231,7 +232,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.20

View File

@@ -59,10 +59,10 @@ com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api.grpc:proto-google-iam-v1:1.0.10
com.google.api:api-common:1.10.1
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax-httpjson:0.79.0
com.google.api:gax:1.62.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
@@ -80,7 +80,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -102,12 +102,13 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.1
com.google.cloud:google-cloud-core:1.94.3
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.113.12
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
@@ -118,7 +119,7 @@ com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
@@ -138,8 +139,8 @@ com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.protobuf:protobuf-java-util:3.15.3
com.google.protobuf:protobuf-java:3.15.3
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.googlecode.charts4j:charts4j:1.3
@@ -231,7 +232,7 @@ org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:3.7.0
org.checkerframework:checker-qual:3.8.0
org.codehaus.jackson:jackson-core-asl:1.9.13
org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.20

View File

@@ -12,14 +12,14 @@ com.google.dagger:dagger-producers:2.33
com.google.dagger:dagger-spi:2.33
com.google.dagger:dagger:2.33
com.google.errorprone:error_prone_annotation:2.3.4
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_annotations:2.5.1
com.google.errorprone:error_prone_check_api:2.3.4
com.google.errorprone:error_prone_core:2.3.4
com.google.errorprone:error_prone_type_annotations:2.3.4
com.google.errorprone:javac-shaded:9-dev-r4023-3
com.google.googlejavaformat:google-java-format:1.5
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:30.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.google.protobuf:protobuf-java:3.4.0
@@ -30,7 +30,7 @@ javax.inject:javax.inject:1
javax.persistence:javax.persistence-api:2.2
net.ltgt.gradle.incap:incap:0.2
org.checkerframework:checker-compat-qual:2.5.3
org.checkerframework:checker-qual:3.5.0
org.checkerframework:checker-qual:3.8.0
org.checkerframework:dataflow:3.0.0
org.checkerframework:javacutil:3.0.0
org.jetbrains.kotlin:kotlin-stdlib-common:1.4.20

View File

@@ -6,10 +6,10 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
com.fasterxml.jackson.core:jackson-annotations:2.12.1
com.fasterxml.jackson.core:jackson-core:2.12.1
com.fasterxml.jackson.core:jackson-databind:2.12.1
com.fasterxml.jackson:jackson-bom:2.12.1
com.fasterxml.jackson.core:jackson-annotations:2.12.3
com.fasterxml.jackson.core:jackson-core:2.12.3
com.fasterxml.jackson.core:jackson-databind:2.12.3
com.fasterxml.jackson:jackson-bom:2.12.3
com.fasterxml:classmate:1.5.1
com.github.docker-java:docker-java-api:3.2.7
com.github.docker-java:docker-java-transport-zerodep:3.2.7
@@ -28,7 +28,7 @@ com.google.api-client:google-api-client-appengine:1.31.3
com.google.api-client:google-api-client-jackson2:1.30.10
com.google.api-client:google-api-client-java6:1.31.3
com.google.api-client:google-api-client-servlet:1.31.3
com.google.api-client:google-api-client:1.31.3
com.google.api-client:google-api-client:1.31.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:1.5.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.105.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.105.5
@@ -54,12 +54,12 @@ com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:1.4.0
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api:api-common:1.10.1
com.google.api.grpc:proto-google-common-protos:2.3.2
com.google.api.grpc:proto-google-iam-v1:1.0.14
com.google.api:api-common:1.10.3
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax:1.62.0
com.google.api:gax-httpjson:0.81.0
com.google.api:gax:1.65.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
com.google.apis:google-api-services-bigquery:v2-rev20200916-1.30.10
@@ -76,7 +76,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -84,10 +84,10 @@ com.google.appengine:appengine-api-1.0-sdk:1.9.86
com.google.appengine:appengine-api-stubs:1.9.86
com.google.appengine:appengine-remote-api:1.9.86
com.google.appengine:appengine-testing:1.9.86
com.google.auth:google-auth-library-credentials:0.24.1
com.google.auth:google-auth-library-oauth2-http:0.24.1
com.google.auth:google-auth-library-credentials:0.26.0
com.google.auth:google-auth-library-oauth2-http:0.26.0
com.google.auto.service:auto-service-annotations:1.0-rc7
com.google.auto.value:auto-value-annotations:1.7.4
com.google.auto.value:auto-value-annotations:1.8.1
com.google.auto.value:auto-value:1.7.4
com.google.cloud.bigdataoss:gcsio:2.1.6
com.google.cloud.bigdataoss:util:2.1.6
@@ -98,32 +98,34 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.8
com.google.cloud:google-cloud-core:1.95.0
com.google.cloud:google-cloud-nio:0.123.2
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.115.0
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
com.google.dagger:dagger:2.33
com.google.errorprone:error_prone_annotations:2.5.1
com.google.errorprone:error_prone_annotations:2.7.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava-testlib:30.1-jre
com.google.guava:guava:30.1-jre
com.google.guava:guava-testlib:30.1.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0
com.google.http-client:google-http-client-gson:1.39.0
com.google.http-client:google-http-client-jackson2:1.39.0
com.google.http-client:google-http-client-apache-v2:1.39.2
com.google.http-client:google-http-client-appengine:1.39.2
com.google.http-client:google-http-client-gson:1.39.2
com.google.http-client:google-http-client-jackson2:1.39.2
com.google.http-client:google-http-client-protobuf:1.33.0
com.google.http-client:google-http-client:1.39.0
com.google.http-client:google-http-client:1.39.2
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
@@ -135,9 +137,9 @@ com.google.oauth-client:google-oauth-client-appengine:1.31.4
com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.oauth-client:google-oauth-client:1.31.5
com.google.protobuf:protobuf-java-util:3.17.2
com.google.protobuf:protobuf-java:3.17.2
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.google.truth.extensions:truth-java8-extension:1.1.2
@@ -161,7 +163,7 @@ io.github.classgraph:classgraph:4.8.102
io.grpc:grpc-alts:1.36.0
io.grpc:grpc-api:1.36.0
io.grpc:grpc-auth:1.36.0
io.grpc:grpc-context:1.36.0
io.grpc:grpc-context:1.37.1
io.grpc:grpc-core:1.36.0
io.grpc:grpc-grpclb:1.36.0
io.grpc:grpc-netty-shaded:1.36.0
@@ -199,7 +201,7 @@ javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.10.5
junit:junit:4.13.1
junit:junit:4.13.2
net.bytebuddy:byte-buddy-agent:1.10.19
net.bytebuddy:byte-buddy:1.10.19
net.java.dev.jna:jna:5.5.0
@@ -307,7 +309,7 @@ org.testcontainers:junit-jupiter:1.15.2
org.testcontainers:postgresql:1.15.2
org.testcontainers:selenium:1.15.2
org.testcontainers:testcontainers:1.15.2
org.threeten:threetenbp:1.5.0
org.threeten:threetenbp:1.5.1
org.tukaani:xz:1.5
org.w3c.css:sac:1.3
org.xerial.snappy:snappy-java:1.1.4

View File

@@ -6,10 +6,10 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
com.fasterxml.jackson.core:jackson-annotations:2.12.1
com.fasterxml.jackson.core:jackson-core:2.12.1
com.fasterxml.jackson.core:jackson-databind:2.12.1
com.fasterxml.jackson:jackson-bom:2.12.1
com.fasterxml.jackson.core:jackson-annotations:2.12.3
com.fasterxml.jackson.core:jackson-core:2.12.3
com.fasterxml.jackson.core:jackson-databind:2.12.3
com.fasterxml.jackson:jackson-bom:2.12.3
com.fasterxml:classmate:1.5.1
com.github.docker-java:docker-java-api:3.2.7
com.github.docker-java:docker-java-transport-zerodep:3.2.7
@@ -27,7 +27,7 @@ com.google.api-client:google-api-client-appengine:1.31.3
com.google.api-client:google-api-client-jackson2:1.30.10
com.google.api-client:google-api-client-java6:1.31.3
com.google.api-client:google-api-client-servlet:1.31.3
com.google.api-client:google-api-client:1.31.3
com.google.api-client:google-api-client:1.31.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:1.5.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.105.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.105.5
@@ -53,12 +53,12 @@ com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:1.4.0
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api:api-common:1.10.1
com.google.api.grpc:proto-google-common-protos:2.3.2
com.google.api.grpc:proto-google-iam-v1:1.0.14
com.google.api:api-common:1.10.3
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax:1.62.0
com.google.api:gax-httpjson:0.81.0
com.google.api:gax:1.65.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
com.google.apis:google-api-services-bigquery:v2-rev20200916-1.30.10
@@ -75,7 +75,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -83,10 +83,10 @@ com.google.appengine:appengine-api-1.0-sdk:1.9.86
com.google.appengine:appengine-api-stubs:1.9.86
com.google.appengine:appengine-remote-api:1.9.86
com.google.appengine:appengine-testing:1.9.86
com.google.auth:google-auth-library-credentials:0.24.1
com.google.auth:google-auth-library-oauth2-http:0.24.1
com.google.auth:google-auth-library-credentials:0.26.0
com.google.auth:google-auth-library-oauth2-http:0.26.0
com.google.auto.service:auto-service-annotations:1.0-rc7
com.google.auto.value:auto-value-annotations:1.7.4
com.google.auto.value:auto-value-annotations:1.8.1
com.google.auto.value:auto-value:1.7.4
com.google.cloud.bigdataoss:gcsio:2.1.6
com.google.cloud.bigdataoss:util:2.1.6
@@ -97,31 +97,33 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.8
com.google.cloud:google-cloud-core:1.95.0
com.google.cloud:google-cloud-nio:0.123.2
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.115.0
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
com.google.dagger:dagger:2.33
com.google.errorprone:error_prone_annotations:2.5.1
com.google.errorprone:error_prone_annotations:2.7.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava-testlib:30.1-jre
com.google.guava:guava:30.1-jre
com.google.guava:guava-testlib:30.1.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0
com.google.http-client:google-http-client-gson:1.39.0
com.google.http-client:google-http-client-jackson2:1.39.0
com.google.http-client:google-http-client-apache-v2:1.39.2
com.google.http-client:google-http-client-appengine:1.39.2
com.google.http-client:google-http-client-gson:1.39.2
com.google.http-client:google-http-client-jackson2:1.39.2
com.google.http-client:google-http-client-protobuf:1.33.0
com.google.http-client:google-http-client:1.39.0
com.google.http-client:google-http-client:1.39.2
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
@@ -133,9 +135,9 @@ com.google.oauth-client:google-oauth-client-appengine:1.31.4
com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.14.0
com.google.protobuf:protobuf-java:3.15.2
com.google.oauth-client:google-oauth-client:1.31.5
com.google.protobuf:protobuf-java-util:3.17.2
com.google.protobuf:protobuf-java:3.17.2
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.google.truth.extensions:truth-java8-extension:1.1.2
@@ -159,7 +161,7 @@ io.github.classgraph:classgraph:4.8.102
io.grpc:grpc-alts:1.36.0
io.grpc:grpc-api:1.36.0
io.grpc:grpc-auth:1.36.0
io.grpc:grpc-context:1.36.0
io.grpc:grpc-context:1.37.1
io.grpc:grpc-core:1.36.0
io.grpc:grpc-grpclb:1.36.0
io.grpc:grpc-netty-shaded:1.36.0
@@ -194,7 +196,7 @@ javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.10.5
junit:junit:4.13.1
junit:junit:4.13.2
net.bytebuddy:byte-buddy-agent:1.10.19
net.bytebuddy:byte-buddy:1.10.19
net.java.dev.jna:jna:5.5.0
@@ -301,7 +303,7 @@ org.testcontainers:junit-jupiter:1.15.2
org.testcontainers:postgresql:1.15.2
org.testcontainers:selenium:1.15.2
org.testcontainers:testcontainers:1.15.2
org.threeten:threetenbp:1.5.0
org.threeten:threetenbp:1.5.1
org.tukaani:xz:1.5
org.w3c.css:sac:1.3
org.xerial.snappy:snappy-java:1.1.4

View File

@@ -10,10 +10,10 @@ com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
com.fasterxml.jackson.core:jackson-annotations:2.12.1
com.fasterxml.jackson.core:jackson-core:2.12.1
com.fasterxml.jackson.core:jackson-databind:2.12.1
com.fasterxml.jackson:jackson-bom:2.12.1
com.fasterxml.jackson.core:jackson-annotations:2.12.3
com.fasterxml.jackson.core:jackson-core:2.12.3
com.fasterxml.jackson.core:jackson-databind:2.12.3
com.fasterxml.jackson:jackson-bom:2.12.3
com.fasterxml:classmate:1.5.1
com.github.docker-java:docker-java-api:3.2.7
com.github.docker-java:docker-java-transport-zerodep:3.2.7
@@ -32,7 +32,7 @@ com.google.api-client:google-api-client-appengine:1.31.3
com.google.api-client:google-api-client-jackson2:1.30.10
com.google.api-client:google-api-client-java6:1.31.3
com.google.api-client:google-api-client-servlet:1.31.3
com.google.api-client:google-api-client:1.31.3
com.google.api-client:google-api-client:1.31.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:1.5.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.105.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.105.5
@@ -58,12 +58,12 @@ com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:1.4.0
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api:api-common:1.10.1
com.google.api.grpc:proto-google-common-protos:2.3.2
com.google.api.grpc:proto-google-iam-v1:1.0.14
com.google.api:api-common:1.10.3
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax:1.62.0
com.google.api:gax-httpjson:0.81.0
com.google.api:gax:1.65.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
com.google.apis:google-api-services-bigquery:v2-rev20200916-1.30.10
@@ -80,7 +80,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -88,10 +88,10 @@ com.google.appengine:appengine-api-1.0-sdk:1.9.86
com.google.appengine:appengine-api-stubs:1.9.86
com.google.appengine:appengine-remote-api:1.9.86
com.google.appengine:appengine-testing:1.9.86
com.google.auth:google-auth-library-credentials:0.24.1
com.google.auth:google-auth-library-oauth2-http:0.24.1
com.google.auth:google-auth-library-credentials:0.26.0
com.google.auth:google-auth-library-oauth2-http:0.26.0
com.google.auto.service:auto-service-annotations:1.0-rc7
com.google.auto.value:auto-value-annotations:1.7.4
com.google.auto.value:auto-value-annotations:1.8.1
com.google.auto.value:auto-value:1.7.4
com.google.cloud.bigdataoss:gcsio:2.1.6
com.google.cloud.bigdataoss:util:2.1.6
@@ -103,32 +103,34 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.8
com.google.cloud:google-cloud-core:1.95.0
com.google.cloud:google-cloud-nio:0.123.2
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.115.0
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
com.google.dagger:dagger:2.33
com.google.errorprone:error_prone_annotations:2.5.1
com.google.errorprone:error_prone_annotations:2.7.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava-testlib:30.1-jre
com.google.guava:guava:30.1-jre
com.google.guava:guava-testlib:30.1.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0
com.google.http-client:google-http-client-gson:1.39.0
com.google.http-client:google-http-client-jackson2:1.39.0
com.google.http-client:google-http-client-apache-v2:1.39.2
com.google.http-client:google-http-client-appengine:1.39.2
com.google.http-client:google-http-client-gson:1.39.2
com.google.http-client:google-http-client-jackson2:1.39.2
com.google.http-client:google-http-client-protobuf:1.33.0
com.google.http-client:google-http-client:1.39.0
com.google.http-client:google-http-client:1.39.2
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
@@ -140,9 +142,9 @@ com.google.oauth-client:google-oauth-client-appengine:1.31.4
com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.oauth-client:google-oauth-client:1.31.5
com.google.protobuf:protobuf-java-util:3.17.2
com.google.protobuf:protobuf-java:3.17.2
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.google.truth.extensions:truth-java8-extension:1.1.2
@@ -170,7 +172,7 @@ io.github.java-diff-utils:java-diff-utils:4.9
io.grpc:grpc-alts:1.36.0
io.grpc:grpc-api:1.36.0
io.grpc:grpc-auth:1.36.0
io.grpc:grpc-context:1.36.0
io.grpc:grpc-context:1.37.1
io.grpc:grpc-core:1.36.0
io.grpc:grpc-grpclb:1.36.0
io.grpc:grpc-netty-shaded:1.36.0
@@ -208,7 +210,7 @@ javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.10.5
junit:junit:4.13.1
junit:junit:4.13.2
net.arnx:nashorn-promise:0.1.1
net.bytebuddy:byte-buddy-agent:1.10.19
net.bytebuddy:byte-buddy:1.10.19
@@ -320,7 +322,7 @@ org.testcontainers:junit-jupiter:1.15.2
org.testcontainers:postgresql:1.15.2
org.testcontainers:selenium:1.15.2
org.testcontainers:testcontainers:1.15.2
org.threeten:threetenbp:1.5.0
org.threeten:threetenbp:1.5.1
org.tukaani:xz:1.5
org.w3c.css:sac:1.3
org.webjars.npm:viz.js-for-graphviz-java:2.1.3

View File

@@ -10,10 +10,10 @@ com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
com.fasterxml.jackson.core:jackson-annotations:2.12.1
com.fasterxml.jackson.core:jackson-core:2.12.1
com.fasterxml.jackson.core:jackson-databind:2.12.1
com.fasterxml.jackson:jackson-bom:2.12.1
com.fasterxml.jackson.core:jackson-annotations:2.12.3
com.fasterxml.jackson.core:jackson-core:2.12.3
com.fasterxml.jackson.core:jackson-databind:2.12.3
com.fasterxml.jackson:jackson-bom:2.12.3
com.fasterxml:classmate:1.5.1
com.github.docker-java:docker-java-api:3.2.7
com.github.docker-java:docker-java-transport-zerodep:3.2.7
@@ -32,7 +32,7 @@ com.google.api-client:google-api-client-appengine:1.31.3
com.google.api-client:google-api-client-jackson2:1.30.10
com.google.api-client:google-api-client-java6:1.31.3
com.google.api-client:google-api-client-servlet:1.31.3
com.google.api-client:google-api-client:1.31.3
com.google.api-client:google-api-client:1.31.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:1.5.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.105.5
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.105.5
@@ -58,12 +58,12 @@ com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:1.4.0
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:2.0.2
com.google.api.grpc:proto-google-cloud-spanner-v1:2.0.2
com.google.api.grpc:proto-google-common-protos:2.1.0
com.google.api.grpc:proto-google-iam-v1:1.0.9
com.google.api:api-common:1.10.1
com.google.api.grpc:proto-google-common-protos:2.3.2
com.google.api.grpc:proto-google-iam-v1:1.0.14
com.google.api:api-common:1.10.3
com.google.api:gax-grpc:1.62.0
com.google.api:gax-httpjson:0.76.1
com.google.api:gax:1.62.0
com.google.api:gax-httpjson:0.81.0
com.google.api:gax:1.65.0
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0
com.google.apis:google-api-services-appengine:v1-rev130-1.25.0
com.google.apis:google-api-services-bigquery:v2-rev20200916-1.30.10
@@ -80,7 +80,7 @@ com.google.apis:google-api-services-monitoring:v3-rev540-1.25.0
com.google.apis:google-api-services-pubsub:v1-rev20200713-1.30.10
com.google.apis:google-api-services-sheets:v4-rev612-1.25.0
com.google.apis:google-api-services-sqladmin:v1beta4-rev20210119-1.31.0
com.google.apis:google-api-services-storage:v1-rev20200927-1.30.10
com.google.apis:google-api-services-storage:v1-rev20210127-1.31.0
com.google.appengine.tools:appengine-gcs-client:0.8.1
com.google.appengine.tools:appengine-mapreduce:0.9
com.google.appengine.tools:appengine-pipeline:0.2.13
@@ -88,10 +88,10 @@ com.google.appengine:appengine-api-1.0-sdk:1.9.86
com.google.appengine:appengine-api-stubs:1.9.86
com.google.appengine:appengine-remote-api:1.9.86
com.google.appengine:appengine-testing:1.9.86
com.google.auth:google-auth-library-credentials:0.24.1
com.google.auth:google-auth-library-oauth2-http:0.24.1
com.google.auth:google-auth-library-credentials:0.26.0
com.google.auth:google-auth-library-oauth2-http:0.26.0
com.google.auto.service:auto-service-annotations:1.0-rc7
com.google.auto.value:auto-value-annotations:1.7.4
com.google.auto.value:auto-value-annotations:1.8.1
com.google.auto.value:auto-value:1.7.4
com.google.cloud.bigdataoss:gcsio:2.1.6
com.google.cloud.bigdataoss:util:2.1.6
@@ -103,32 +103,34 @@ com.google.cloud:google-cloud-bigquery:1.122.2
com.google.cloud:google-cloud-bigquerystorage:1.5.5
com.google.cloud:google-cloud-bigtable:1.14.0
com.google.cloud:google-cloud-core-grpc:1.93.9
com.google.cloud:google-cloud-core-http:1.93.9
com.google.cloud:google-cloud-core:1.93.9
com.google.cloud:google-cloud-core-http:1.94.8
com.google.cloud:google-cloud-core:1.95.0
com.google.cloud:google-cloud-nio:0.123.2
com.google.cloud:google-cloud-pubsub:1.110.0
com.google.cloud:google-cloud-pubsublite:0.7.0
com.google.cloud:google-cloud-secretmanager:1.4.0
com.google.cloud:google-cloud-spanner:2.0.2
com.google.cloud:google-cloud-storage:1.115.0
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.8.6
com.google.common.html.types:types:1.0.6
com.google.dagger:dagger:2.33
com.google.errorprone:error_prone_annotations:2.5.1
com.google.errorprone:error_prone_annotations:2.7.1
com.google.escapevelocity:escapevelocity:0.9.1
com.google.flogger:flogger-system-backend:0.5.1
com.google.flogger:flogger:0.5.1
com.google.flogger:google-extensions:0.5.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava-testlib:30.1-jre
com.google.guava:guava:30.1-jre
com.google.guava:guava-testlib:30.1.1-jre
com.google.guava:guava:30.1.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.9.0
com.google.http-client:google-http-client-apache-v2:1.39.0
com.google.http-client:google-http-client-appengine:1.39.0
com.google.http-client:google-http-client-gson:1.39.0
com.google.http-client:google-http-client-jackson2:1.39.0
com.google.http-client:google-http-client-apache-v2:1.39.2
com.google.http-client:google-http-client-appengine:1.39.2
com.google.http-client:google-http-client-gson:1.39.2
com.google.http-client:google-http-client-jackson2:1.39.2
com.google.http-client:google-http-client-protobuf:1.33.0
com.google.http-client:google-http-client:1.39.0
com.google.http-client:google-http-client:1.39.2
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
@@ -140,9 +142,9 @@ com.google.oauth-client:google-oauth-client-appengine:1.31.4
com.google.oauth-client:google-oauth-client-java6:1.31.4
com.google.oauth-client:google-oauth-client-jetty:1.31.4
com.google.oauth-client:google-oauth-client-servlet:1.31.4
com.google.oauth-client:google-oauth-client:1.31.4
com.google.protobuf:protobuf-java-util:3.15.2
com.google.protobuf:protobuf-java:3.15.2
com.google.oauth-client:google-oauth-client:1.31.5
com.google.protobuf:protobuf-java-util:3.17.2
com.google.protobuf:protobuf-java:3.17.2
com.google.re2j:re2j:1.6
com.google.template:soy:2021-02-01
com.google.truth.extensions:truth-java8-extension:1.1.2
@@ -170,7 +172,7 @@ io.github.java-diff-utils:java-diff-utils:4.9
io.grpc:grpc-alts:1.36.0
io.grpc:grpc-api:1.36.0
io.grpc:grpc-auth:1.36.0
io.grpc:grpc-context:1.36.0
io.grpc:grpc-context:1.37.1
io.grpc:grpc-core:1.36.0
io.grpc:grpc-grpclb:1.36.0
io.grpc:grpc-netty-shaded:1.36.0
@@ -208,7 +210,7 @@ javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.10.5
junit:junit:4.13.1
junit:junit:4.13.2
net.arnx:nashorn-promise:0.1.1
net.bytebuddy:byte-buddy-agent:1.10.19
net.bytebuddy:byte-buddy:1.10.19
@@ -321,7 +323,7 @@ org.testcontainers:junit-jupiter:1.15.2
org.testcontainers:postgresql:1.15.2
org.testcontainers:selenium:1.15.2
org.testcontainers:testcontainers:1.15.2
org.threeten:threetenbp:1.5.0
org.threeten:threetenbp:1.5.1
org.tukaani:xz:1.5
org.w3c.css:sac:1.3
org.webjars.npm:viz.js-for-graphviz-java:2.1.3

View File

@@ -18,8 +18,10 @@ import static com.google.appengine.api.ThreadManager.currentRequestThreadFactory
import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator;
import static google.registry.backup.ExportCommitLogDiffAction.LOWER_CHECKPOINT_TIME_PARAM;
import static google.registry.backup.ExportCommitLogDiffAction.UPPER_CHECKPOINT_TIME_PARAM;
import static google.registry.backup.RestoreCommitLogsAction.BUCKET_OVERRIDE_PARAM;
import static google.registry.backup.RestoreCommitLogsAction.FROM_TIME_PARAM;
import static google.registry.backup.RestoreCommitLogsAction.TO_TIME_PARAM;
import static google.registry.request.RequestParameters.extractOptionalParameter;
import static google.registry.request.RequestParameters.extractRequiredDatetimeParameter;
import static google.registry.request.RequestParameters.extractRequiredParameter;
import static java.util.concurrent.Executors.newFixedThreadPool;
@@ -32,6 +34,9 @@ import google.registry.cron.CommitLogFanoutAction;
import google.registry.request.HttpException.BadRequestException;
import google.registry.request.Parameter;
import java.lang.annotation.Documented;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Qualifier;
import javax.servlet.http.HttpServletRequest;
import org.joda.time.DateTime;
@@ -75,6 +80,12 @@ public final class BackupModule {
return extractRequiredDatetimeParameter(req, UPPER_CHECKPOINT_TIME_PARAM);
}
@Provides
@Parameter(BUCKET_OVERRIDE_PARAM)
static Optional<String> provideBucketOverride(HttpServletRequest req) {
return extractOptionalParameter(req, BUCKET_OVERRIDE_PARAM);
}
@Provides
@Parameter(FROM_TIME_PARAM)
static DateTime provideFromTime(HttpServletRequest req) {
@@ -92,4 +103,9 @@ public final class BackupModule {
static ListeningExecutorService provideListeningExecutorService() {
return listeningDecorator(newFixedThreadPool(NUM_THREADS, currentRequestThreadFactory()));
}
@Provides
static ScheduledExecutorService provideScheduledExecutorService() {
return Executors.newSingleThreadScheduledExecutor();
}
}

View File

@@ -56,12 +56,16 @@ public class BackupUtils {
*
* <p>The iterator reads from the stream on demand, and as such will fail if the stream is closed.
*/
public static Iterator<ImmutableObject> createDeserializingIterator(final InputStream input) {
public static Iterator<ImmutableObject> createDeserializingIterator(
final InputStream input, boolean withAppIdOverride) {
return new AbstractIterator<ImmutableObject>() {
@Override
protected ImmutableObject computeNext() {
EntityProto proto = new EntityProto();
if (proto.parseDelimitedFrom(input)) { // False means end of stream; other errors throw.
if (withAppIdOverride) {
proto = EntityImports.fixEntity(proto);
}
return auditedOfy().load().fromEntity(EntityTranslator.createFromPb(proto));
}
return endOfData();
@@ -70,6 +74,7 @@ public class BackupUtils {
}
public static ImmutableList<ImmutableObject> deserializeEntities(byte[] bytes) {
return ImmutableList.copyOf(createDeserializingIterator(new ByteArrayInputStream(bytes)));
return ImmutableList.copyOf(
createDeserializingIterator(new ByteArrayInputStream(bytes), false));
}
}

View File

@@ -59,7 +59,7 @@ public final class CommitLogImports {
InputStream inputStream) {
try (AppEngineEnvironment appEngineEnvironment = new AppEngineEnvironment();
InputStream input = new BufferedInputStream(inputStream)) {
Iterator<ImmutableObject> commitLogs = createDeserializingIterator(input);
Iterator<ImmutableObject> commitLogs = createDeserializingIterator(input, false);
checkState(commitLogs.hasNext());
checkState(commitLogs.next() instanceof CommitLogCheckpoint);

View File

@@ -66,6 +66,8 @@ import org.joda.time.Duration;
service = Action.Service.BACKEND,
path = "/_dr/task/deleteOldCommitLogs",
auth = Auth.AUTH_INTERNAL_OR_ADMIN)
// No longer needed in SQL. Subject to future removal.
@Deprecated
public final class DeleteOldCommitLogsAction implements Runnable {
private static final int NUM_MAP_SHARDS = 20;

View File

@@ -0,0 +1,115 @@
// Copyright 2021 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.backup;
import com.google.apphosting.api.ApiProxy;
import com.google.storage.onestore.v3.OnestoreEntity;
import com.google.storage.onestore.v3.OnestoreEntity.EntityProto;
import com.google.storage.onestore.v3.OnestoreEntity.Path;
import com.google.storage.onestore.v3.OnestoreEntity.Property.Meaning;
import com.google.storage.onestore.v3.OnestoreEntity.PropertyValue.ReferenceValue;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/** Utilities for handling imported Datastore entities. */
public class EntityImports {
/**
* Transitively sets the {@code appId} of all keys in a foreign entity to that of the current
* system.
*/
public static EntityProto fixEntity(EntityProto entityProto) {
String currentAappId = ApiProxy.getCurrentEnvironment().getAppId();
if (Objects.equals(currentAappId, entityProto.getKey().getApp())) {
return entityProto;
}
return fixEntity(entityProto, currentAappId);
}
private static EntityProto fixEntity(EntityProto entityProto, String appId) {
if (entityProto.hasKey()) {
fixKey(entityProto, appId);
}
for (OnestoreEntity.Property property : entityProto.mutablePropertys()) {
fixProperty(property, appId);
}
for (OnestoreEntity.Property property : entityProto.mutableRawPropertys()) {
fixProperty(property, appId);
}
// CommitLogMutation embeds an entity as bytes, which needs additional fixes.
if (isCommitLogMutation(entityProto)) {
fixMutationEntityProtoBytes(entityProto, appId);
}
return entityProto;
}
private static boolean isCommitLogMutation(EntityProto entityProto) {
if (!entityProto.hasKey()) {
return false;
}
Path path = entityProto.getKey().getPath();
if (path.elementSize() == 0) {
return false;
}
return Objects.equals(
path.getElement(path.elementSize() - 1).getType(StandardCharsets.UTF_8),
"CommitLogMutation");
}
private static void fixMutationEntityProtoBytes(EntityProto entityProto, String appId) {
for (OnestoreEntity.Property property : entityProto.mutableRawPropertys()) {
if (Objects.equals(property.getName(), "entityProtoBytes")) {
OnestoreEntity.PropertyValue value = property.getValue();
EntityProto fixedProto =
fixEntity(bytesToEntityProto(value.getStringValueAsBytes()), appId);
value.setStringValueAsBytes(fixedProto.toByteArray());
return;
}
}
}
private static void fixKey(EntityProto entityProto, String appId) {
entityProto.getMutableKey().setApp(appId);
}
private static void fixKey(ReferenceValue referenceValue, String appId) {
referenceValue.setApp(appId);
}
private static void fixProperty(OnestoreEntity.Property property, String appId) {
OnestoreEntity.PropertyValue value = property.getMutableValue();
if (value.hasReferenceValue()) {
fixKey(value.getMutableReferenceValue(), appId);
return;
}
if (property.getMeaningEnum().equals(Meaning.ENTITY_PROTO)) {
EntityProto embeddedProto = bytesToEntityProto(value.getStringValueAsBytes());
fixEntity(embeddedProto, appId);
value.setStringValueAsBytes(embeddedProto.toByteArray());
}
}
private static EntityProto bytesToEntityProto(byte[] bytes) {
EntityProto entityProto = new EntityProto();
boolean isParsed = entityProto.parseFrom(bytes);
if (!isParsed) {
throw new IllegalStateException("Failed to parse raw bytes as EntityProto.");
}
return entityProto;
}
}

View File

@@ -28,18 +28,17 @@ import static google.registry.model.ofy.CommitLogBucket.getBucketKey;
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static google.registry.util.DateTimeUtils.isAtOrAfter;
import static java.nio.channels.Channels.newOutputStream;
import static java.util.Comparator.comparingLong;
import com.google.appengine.tools.cloudstorage.GcsFileOptions;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.cloud.storage.BlobId;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig.Config;
import google.registry.gcs.GcsUtils;
import google.registry.model.ImmutableObject;
import google.registry.model.ofy.CommitLogBucket;
import google.registry.model.ofy.CommitLogCheckpoint;
@@ -74,7 +73,8 @@ public final class ExportCommitLogDiffAction implements Runnable {
public static final String DIFF_FILE_PREFIX = "commit_diff_until_";
@Inject GcsService gcsService;
@Inject GcsUtils gcsUtils;
@Inject @Config("commitLogGcsBucket") String gcsBucket;
@Inject @Config("commitLogDiffExportBatchSize") int batchSize;
@Inject @Parameter(LOWER_CHECKPOINT_TIME_PARAM) DateTime lowerCheckpointTime;
@@ -102,13 +102,13 @@ public final class ExportCommitLogDiffAction implements Runnable {
List<Key<CommitLogManifest>> sortedKeys = loadAllDiffKeys(lowerCheckpoint, upperCheckpoint);
logger.atInfo().log("Found %d manifests to export", sortedKeys.size());
// Open an output channel to GCS, wrapped in a stream for convenience.
try (OutputStream gcsStream = newOutputStream(gcsService.createOrReplace(
new GcsFilename(gcsBucket, DIFF_FILE_PREFIX + upperCheckpointTime),
new GcsFileOptions.Builder()
.addUserMetadata(LOWER_BOUND_CHECKPOINT, lowerCheckpointTime.toString())
.addUserMetadata(UPPER_BOUND_CHECKPOINT, upperCheckpointTime.toString())
.addUserMetadata(NUM_TRANSACTIONS, Integer.toString(sortedKeys.size()))
.build()))) {
try (OutputStream gcsStream =
gcsUtils.openOutputStream(
BlobId.of(gcsBucket, DIFF_FILE_PREFIX + upperCheckpointTime),
ImmutableMap.of(
LOWER_BOUND_CHECKPOINT, lowerCheckpointTime.toString(),
UPPER_BOUND_CHECKPOINT, upperCheckpointTime.toString(),
NUM_TRANSACTIONS, Integer.toString(sortedKeys.size())))) {
// Export the upper checkpoint itself.
serializeEntity(upperCheckpoint, gcsStream);
// If there are no manifests to export, stop early, now that we've written out the file with

View File

@@ -21,22 +21,22 @@ import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
import static google.registry.util.DateTimeUtils.latestOf;
import com.google.appengine.tools.cloudstorage.GcsFileMetadata;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.appengine.tools.cloudstorage.ListItem;
import com.google.appengine.tools.cloudstorage.ListOptions;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.UncheckedExecutionException;
import dagger.Lazy;
import google.registry.backup.BackupModule.Backups;
import google.registry.config.RegistryConfig.Config;
import google.registry.gcs.GcsUtils;
import java.io.IOException;
import java.util.Iterator;
import java.time.Duration;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.joda.time.DateTime;
@@ -46,33 +46,49 @@ class GcsDiffFileLister {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Inject GcsService gcsService;
@Inject @Config("commitLogGcsBucket") String gcsBucket;
@Inject @Backups ListeningExecutorService executor;
@Inject GcsDiffFileLister() {}
/** Timeout for retrieving per-file information from GCS. */
private static final Duration FILE_INFO_TIMEOUT_DURATION = Duration.ofMinutes(1);
@Inject GcsUtils gcsUtils;
@Inject @Backups Lazy<ListeningExecutorService> lazyExecutor;
@Inject ScheduledExecutorService scheduledExecutorService;
@Inject
GcsDiffFileLister() {}
/**
* Traverses the sequence of diff files backwards from checkpointTime and inserts the file
* metadata into "sequence". Returns true if a complete sequence was discovered, false if one or
* metadata into "sequence". Returns true if a complete sequence was discovered, false if one or
* more files are missing.
*
* @throws UncheckedExecutionException wrapping a {@link java.util.concurrent.TimeoutException} if
* the GCS call fails to finish within one minute, or wrapping any other exception if
* something else goes wrong.
*/
private boolean constructDiffSequence(
Map<DateTime, ListenableFuture<GcsFileMetadata>> upperBoundTimesToMetadata,
String gcsBucket,
Map<DateTime, ListenableFuture<BlobInfo>> upperBoundTimesToBlobInfo,
DateTime fromTime,
DateTime lastTime,
TreeMap<DateTime, GcsFileMetadata> sequence) {
TreeMap<DateTime, BlobInfo> sequence) {
DateTime checkpointTime = lastTime;
while (isBeforeOrAt(fromTime, checkpointTime)) {
GcsFileMetadata metadata;
if (upperBoundTimesToMetadata.containsKey(checkpointTime)) {
metadata = Futures.getUnchecked(upperBoundTimesToMetadata.get(checkpointTime));
BlobInfo blobInfo;
if (upperBoundTimesToBlobInfo.containsKey(checkpointTime)) {
blobInfo =
Futures.getUnchecked(
Futures.withTimeout(
upperBoundTimesToBlobInfo.get(checkpointTime),
FILE_INFO_TIMEOUT_DURATION,
scheduledExecutorService));
} else {
String filename = DIFF_FILE_PREFIX + checkpointTime;
logger.atInfo().log("Patching GCS list; discovered file: %s", filename);
metadata = getMetadata(filename);
blobInfo = getBlobInfo(gcsBucket, filename);
// If we hit a gap, quit.
if (metadata == null) {
if (blobInfo == null) {
logger.atInfo().log(
"Gap discovered in sequence terminating at %s, missing file: %s",
sequence.lastKey(), filename);
@@ -80,14 +96,15 @@ class GcsDiffFileLister {
return false;
}
}
sequence.put(checkpointTime, metadata);
checkpointTime = getLowerBoundTime(metadata);
sequence.put(checkpointTime, blobInfo);
checkpointTime = getLowerBoundTime(blobInfo);
}
logger.atInfo().log("Found sequence from %s to %s", checkpointTime, lastTime);
return true;
}
ImmutableList<GcsFileMetadata> listDiffFiles(DateTime fromTime, @Nullable DateTime toTime) {
ImmutableList<BlobInfo> listDiffFiles(
String gcsBucket, DateTime fromTime, @Nullable DateTime toTime) {
logger.atInfo().log("Requested restore from time: %s", fromTime);
if (toTime != null) {
logger.atInfo().log(" Until time: %s", toTime);
@@ -95,66 +112,69 @@ class GcsDiffFileLister {
// List all of the diff files on GCS and build a map from each file's upper checkpoint time
// (extracted from the filename) to its asynchronously-loaded metadata, keeping only files with
// an upper checkpoint time > fromTime.
TreeMap<DateTime, ListenableFuture<GcsFileMetadata>> upperBoundTimesToMetadata
= new TreeMap<>();
Iterator<ListItem> listItems;
TreeMap<DateTime, ListenableFuture<BlobInfo>> upperBoundTimesToBlobInfo = new TreeMap<>();
ImmutableList<String> strippedFilenames;
try {
// TODO(b/23554360): Use a smarter prefixing strategy to speed this up.
listItems = gcsService.list(
gcsBucket,
new ListOptions.Builder().setPrefix(DIFF_FILE_PREFIX).build());
strippedFilenames = gcsUtils.listFolderObjects(gcsBucket, DIFF_FILE_PREFIX);
} catch (IOException e) {
throw new RuntimeException(e);
}
DateTime lastUpperBoundTime = START_OF_TIME;
while (listItems.hasNext()) {
final String filename = listItems.next().getName();
DateTime upperBoundTime = DateTime.parse(filename.substring(DIFF_FILE_PREFIX.length()));
if (isInRange(upperBoundTime, fromTime, toTime)) {
upperBoundTimesToMetadata.put(upperBoundTime, executor.submit(() -> getMetadata(filename)));
lastUpperBoundTime = latestOf(upperBoundTime, lastUpperBoundTime);
}
}
if (upperBoundTimesToMetadata.isEmpty()) {
logger.atInfo().log("No files found");
return ImmutableList.of();
}
// Reconstruct the sequence of files by traversing backwards from "lastUpperBoundTime" (i.e. the
// last file that we found) and finding its previous file until we either run out of files or
// get to one that precedes "fromTime".
//
// GCS file listing is eventually consistent, so it's possible that we are missing a file. The
// metadata of a file is sufficient to identify the preceding file, so if we start from the
// last file and work backwards we can verify that we have no holes in our chain (although we
// may be missing files at the end).
TreeMap<DateTime, GcsFileMetadata> sequence = new TreeMap<>();
logger.atInfo().log("Restoring until: %s", lastUpperBoundTime);
boolean inconsistentFileSet = !constructDiffSequence(
upperBoundTimesToMetadata, fromTime, lastUpperBoundTime, sequence);
// Verify that all of the elements in the original set are represented in the sequence. If we
// find anything that's not represented, construct a sequence for it.
boolean checkForMoreExtraDiffs = true; // Always loop at least once.
while (checkForMoreExtraDiffs) {
checkForMoreExtraDiffs = false;
for (DateTime key : upperBoundTimesToMetadata.descendingKeySet()) {
if (!isInRange(key, fromTime, toTime)) {
break;
}
if (!sequence.containsKey(key)) {
constructDiffSequence(upperBoundTimesToMetadata, fromTime, key, sequence);
checkForMoreExtraDiffs = true;
inconsistentFileSet = true;
break;
TreeMap<DateTime, BlobInfo> sequence = new TreeMap<>();
try {
for (String strippedFilename : strippedFilenames) {
final String filename = DIFF_FILE_PREFIX + strippedFilename;
DateTime upperBoundTime = DateTime.parse(strippedFilename);
if (isInRange(upperBoundTime, fromTime, toTime)) {
upperBoundTimesToBlobInfo.put(
upperBoundTime, lazyExecutor.get().submit(() -> getBlobInfo(gcsBucket, filename)));
lastUpperBoundTime = latestOf(upperBoundTime, lastUpperBoundTime);
}
}
}
if (upperBoundTimesToBlobInfo.isEmpty()) {
logger.atInfo().log("No files found");
return ImmutableList.of();
}
checkState(
!inconsistentFileSet,
"Unable to compute commit diff history, there are either gaps or forks in the history "
+ "file set. Check log for details.");
// Reconstruct the sequence of files by traversing backwards from "lastUpperBoundTime" (i.e.
// the last file that we found) and finding its previous file until we either run out of files
// or get to one that precedes "fromTime".
//
// GCS file listing is eventually consistent, so it's possible that we are missing a file. The
// metadata of a file is sufficient to identify the preceding file, so if we start from the
// last file and work backwards we can verify that we have no holes in our chain (although we
// may be missing files at the end).
logger.atInfo().log("Restoring until: %s", lastUpperBoundTime);
boolean inconsistentFileSet =
!constructDiffSequence(
gcsBucket, upperBoundTimesToBlobInfo, fromTime, lastUpperBoundTime, sequence);
// Verify that all of the elements in the original set are represented in the sequence. If we
// find anything that's not represented, construct a sequence for it.
boolean checkForMoreExtraDiffs = true; // Always loop at least once.
while (checkForMoreExtraDiffs) {
checkForMoreExtraDiffs = false;
for (DateTime key : upperBoundTimesToBlobInfo.descendingKeySet()) {
if (!isInRange(key, fromTime, toTime)) {
break;
}
if (!sequence.containsKey(key)) {
constructDiffSequence(gcsBucket, upperBoundTimesToBlobInfo, fromTime, key, sequence);
checkForMoreExtraDiffs = true;
inconsistentFileSet = true;
break;
}
}
}
checkState(
!inconsistentFileSet,
"Unable to compute commit diff history, there are either gaps or forks in the history "
+ "file set. Check log for details.");
} finally {
lazyExecutor.get().shutdown();
}
logger.atInfo().log(
"Actual restore from time: %s", getLowerBoundTime(sequence.firstEntry().getValue()));
@@ -171,15 +191,11 @@ class GcsDiffFileLister {
return isBeforeOrAt(start, time) && (end == null || isBeforeOrAt(time, end));
}
private DateTime getLowerBoundTime(GcsFileMetadata metadata) {
return DateTime.parse(metadata.getOptions().getUserMetadata().get(LOWER_BOUND_CHECKPOINT));
private DateTime getLowerBoundTime(BlobInfo blobInfo) {
return DateTime.parse(blobInfo.getMetadata().get(LOWER_BOUND_CHECKPOINT));
}
private GcsFileMetadata getMetadata(String filename) {
try {
return gcsService.getMetadata(new GcsFilename(gcsBucket, filename));
} catch (IOException e) {
throw new RuntimeException(e);
}
private BlobInfo getBlobInfo(String gcsBucket, String filename) {
return gcsUtils.getBlobInfo(BlobId.of(gcsBucket, filename));
}
}

View File

@@ -14,7 +14,9 @@
package google.registry.backup;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.backup.ExportCommitLogDiffAction.DIFF_FILE_PREFIX;
import static google.registry.backup.RestoreCommitLogsAction.DRY_RUN_PARAM;
import static google.registry.model.ofy.EntityWritePriorities.getEntityPriority;
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
@@ -23,15 +25,21 @@ import static org.joda.time.Duration.standardHours;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.tools.cloudstorage.GcsFileMetadata;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.cloud.storage.BlobInfo;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import google.registry.config.RegistryConfig;
import google.registry.config.RegistryConfig.Config;
import google.registry.gcs.GcsUtils;
import google.registry.model.common.DatabaseMigrationStateSchedule;
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
import google.registry.model.common.DatabaseMigrationStateSchedule.ReplayDirection;
import google.registry.model.server.Lock;
import google.registry.model.translators.VKeyTranslatorFactory;
import google.registry.persistence.VKey;
import google.registry.request.Action;
import google.registry.request.Action.Method;
import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.schema.replay.DatastoreEntity;
@@ -39,10 +47,10 @@ import google.registry.schema.replay.DatastoreOnlyEntity;
import google.registry.schema.replay.NonReplicatedEntity;
import google.registry.schema.replay.ReplaySpecializer;
import google.registry.schema.replay.SqlReplayCheckpoint;
import google.registry.util.Clock;
import google.registry.util.RequestStatusChecker;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.util.Optional;
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
@@ -53,31 +61,46 @@ import org.joda.time.Duration;
@Action(
service = Action.Service.BACKEND,
path = ReplayCommitLogsToSqlAction.PATH,
method = Action.Method.POST,
method = Method.POST,
automaticallyPrintOk = true,
auth = Auth.AUTH_INTERNAL_OR_ADMIN)
public class ReplayCommitLogsToSqlAction implements Runnable {
static final String PATH = "/_dr/task/replayCommitLogsToSql";
private static final int BLOCK_SIZE =
1024 * 1024; // Buffer 1mb at a time, for no particular reason.
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Duration LEASE_LENGTH = standardHours(1);
@Inject GcsService gcsService;
private static final Duration LEASE_LENGTH = standardHours(1);
// Stop / pause where we are if we've been replaying for more than five minutes to avoid GAE
// request timeouts
private static final Duration REPLAY_TIMEOUT_DURATION = Duration.standardMinutes(5);
@Inject GcsUtils gcsUtils;
@Inject Response response;
@Inject RequestStatusChecker requestStatusChecker;
@Inject GcsDiffFileLister diffLister;
@Inject Clock clock;
@Inject
@Config("commitLogGcsBucket")
String gcsBucket;
/** If true, will exit after logging the commit log files that would otherwise be replayed. */
@Inject
@Parameter(DRY_RUN_PARAM)
boolean dryRun;
@Inject
ReplayCommitLogsToSqlAction() {}
@Override
public void run() {
if (!RegistryConfig.getCloudSqlReplayCommitLogs()) {
String message = "ReplayCommitLogsToSqlAction was called but disabled in the config.";
logger.atWarning().log(message);
MigrationState state = DatabaseMigrationStateSchedule.getValueAtTime(clock.nowUtc());
if (!state.getReplayDirection().equals(ReplayDirection.DATASTORE_TO_SQL)) {
String message =
String.format(
"Skipping ReplayCommitLogsToSqlAction because we are in migration phase %s.", state);
logger.atInfo().log(message);
// App Engine will retry on any non-2xx status code, which we don't want in this case.
response.setStatus(SC_NO_CONTENT);
response.setPayload(message);
@@ -96,44 +119,86 @@ public class ReplayCommitLogsToSqlAction implements Runnable {
return;
}
try {
replayFiles();
response.setStatus(HttpServletResponse.SC_OK);
logger.atInfo().log("ReplayCommitLogsToSqlAction completed successfully.");
logger.atInfo().log("Beginning replay of commit logs.");
ImmutableList<BlobInfo> commitLogFiles = getFilesToReplay();
if (dryRun) {
response.setStatus(HttpServletResponse.SC_OK);
ImmutableList<String> filenames =
commitLogFiles.stream()
.limit(10)
.map(file -> file.getName())
.collect(toImmutableList());
String dryRunMessage =
"Running in dry-run mode; would have processed %d files. They are (limit 10):\n"
+ Joiner.on('\n').join(filenames);
response.setPayload(dryRunMessage);
logger.atInfo().log(dryRunMessage);
} else {
replayFiles(commitLogFiles);
response.setStatus(HttpServletResponse.SC_OK);
String message = "ReplayCommitLogsToSqlAction completed successfully.";
response.setPayload(message);
logger.atInfo().log(message);
}
} catch (Throwable t) {
String message = "Errored out replaying files.";
logger.atSevere().withCause(t).log(message);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.setPayload(message);
} finally {
lock.ifPresent(Lock::release);
}
}
private void replayFiles() {
private ImmutableList<BlobInfo> getFilesToReplay() {
// Start at the first millisecond we haven't seen yet
DateTime fromTime = jpaTm().transact(() -> SqlReplayCheckpoint.get().plusMillis(1));
logger.atInfo().log("Starting replay from: %s.", fromTime);
// If there's an inconsistent file set, this will throw IllegalStateException and the job
// will try later -- this is likely because an export hasn't finished yet.
ImmutableList<GcsFileMetadata> commitLogFiles =
diffLister.listDiffFiles(fromTime, /* current time */ null);
for (GcsFileMetadata metadata : commitLogFiles) {
// One transaction per GCS file
jpaTm().transact(() -> processFile(metadata));
}
logger.atInfo().log("Replayed %d commit log files to SQL successfully.", commitLogFiles.size());
ImmutableList<BlobInfo> commitLogFiles =
diffLister.listDiffFiles(gcsBucket, fromTime, /* current time */ null);
logger.atInfo().log("Found %d new commit log files to process.", commitLogFiles.size());
return commitLogFiles;
}
private void processFile(GcsFileMetadata metadata) {
try (InputStream input =
Channels.newInputStream(
gcsService.openPrefetchingReadChannel(metadata.getFilename(), 0, BLOCK_SIZE))) {
private void replayFiles(ImmutableList<BlobInfo> commitLogFiles) {
DateTime replayTimeoutTime = clock.nowUtc().plus(REPLAY_TIMEOUT_DURATION);
int processedFiles = 0;
for (BlobInfo metadata : commitLogFiles) {
// One transaction per GCS file
jpaTm().transact(() -> processFile(metadata));
processedFiles++;
if (clock.nowUtc().isAfter(replayTimeoutTime)) {
logger.atInfo().log(
"Reached max execution time after replaying %d files, leaving %d files for next run.",
processedFiles, commitLogFiles.size() - processedFiles);
return;
}
}
logger.atInfo().log("Replayed %d commit log files to SQL successfully.", processedFiles);
}
private void processFile(BlobInfo metadata) {
logger.atInfo().log(
"Processing commit log file %s of size %d B.", metadata.getName(), metadata.getSize());
try (InputStream input = gcsUtils.openInputStream(metadata.getBlobId())) {
// Load and process the Datastore transactions one at a time
ImmutableList<ImmutableList<VersionedEntity>> allTransactions =
CommitLogImports.loadEntitiesByTransaction(input);
logger.atInfo().log(
"Replaying %d transactions from commit log file %s.",
allTransactions.size(), metadata.getName());
allTransactions.forEach(this::replayTransaction);
// if we succeeded, set the last-seen time
DateTime checkpoint =
DateTime.parse(
metadata.getFilename().getObjectName().substring(DIFF_FILE_PREFIX.length()));
DateTime checkpoint = DateTime.parse(metadata.getName().substring(DIFF_FILE_PREFIX.length()));
SqlReplayCheckpoint.set(checkpoint);
logger.atInfo().log("Replayed %d transactions from commit log file.", allTransactions.size());
logger.atInfo().log(
"Replayed %d transactions from commit log file %s.",
allTransactions.size(), metadata.getName());
} catch (IOException e) {
throw new RuntimeException(e);
throw new RuntimeException(
"Errored out while replaying commit log file " + metadata.getName(), e);
}
}

View File

@@ -23,9 +23,9 @@ import static google.registry.model.ofy.ObjectifyService.auditedOfy;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityTranslator;
import com.google.appengine.tools.cloudstorage.GcsFileMetadata;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.cloud.storage.BlobInfo;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.PeekingIterator;
import com.google.common.collect.Streams;
@@ -33,7 +33,9 @@ import com.google.common.flogger.FluentLogger;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Result;
import com.googlecode.objectify.util.ResultNow;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.gcs.GcsUtils;
import google.registry.model.ImmutableObject;
import google.registry.model.ofy.CommitLogBucket;
import google.registry.model.ofy.CommitLogCheckpoint;
@@ -46,10 +48,10 @@ import google.registry.request.auth.Auth;
import google.registry.util.Retrier;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import javax.inject.Inject;
@@ -66,45 +68,57 @@ public class RestoreCommitLogsAction implements Runnable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
static final int BLOCK_SIZE = 1024 * 1024; // Buffer 1mb at a time, for no particular reason.
public static final String PATH = "/_dr/task/restoreCommitLogs";
static final String DRY_RUN_PARAM = "dryRun";
static final String FROM_TIME_PARAM = "fromTime";
static final String TO_TIME_PARAM = "toTime";
static final String BUCKET_OVERRIDE_PARAM = "gcsBucket";
private static final ImmutableSet<RegistryEnvironment> FORBIDDEN_ENVIRONMENTS =
ImmutableSet.of(RegistryEnvironment.PRODUCTION, RegistryEnvironment.SANDBOX);
@Inject GcsUtils gcsUtils;
@Inject GcsService gcsService;
@Inject @Parameter(DRY_RUN_PARAM) boolean dryRun;
@Inject @Parameter(FROM_TIME_PARAM) DateTime fromTime;
@Inject @Parameter(TO_TIME_PARAM) DateTime toTime;
@Inject
@Parameter(BUCKET_OVERRIDE_PARAM)
Optional<String> gcsBucketOverride;
@Inject DatastoreService datastoreService;
@Inject GcsDiffFileLister diffLister;
@Inject
@Config("commitLogGcsBucket")
String defaultGcsBucket;
@Inject Retrier retrier;
@Inject RestoreCommitLogsAction() {}
@Override
public void run() {
checkArgument(
RegistryEnvironment.get() == RegistryEnvironment.ALPHA
|| RegistryEnvironment.get() == RegistryEnvironment.CRASH
|| RegistryEnvironment.get() == RegistryEnvironment.UNITTEST,
"DO NOT RUN ANYWHERE ELSE EXCEPT ALPHA, CRASH OR TESTS.");
!FORBIDDEN_ENVIRONMENTS.contains(RegistryEnvironment.get()),
"DO NOT RUN IN PRODUCTION OR SANDBOX.");
if (dryRun) {
logger.atInfo().log("Running in dryRun mode");
}
List<GcsFileMetadata> diffFiles = diffLister.listDiffFiles(fromTime, toTime);
String gcsBucket = gcsBucketOverride.orElse(defaultGcsBucket);
logger.atInfo().log("Restoring from %s.", gcsBucket);
List<BlobInfo> diffFiles = diffLister.listDiffFiles(gcsBucket, fromTime, toTime);
if (diffFiles.isEmpty()) {
logger.atInfo().log("Nothing to restore");
return;
}
Map<Integer, DateTime> bucketTimestamps = new HashMap<>();
CommitLogCheckpoint lastCheckpoint = null;
for (GcsFileMetadata metadata : diffFiles) {
logger.atInfo().log("Restoring: %s", metadata.getFilename().getObjectName());
try (InputStream input = Channels.newInputStream(
gcsService.openPrefetchingReadChannel(metadata.getFilename(), 0, BLOCK_SIZE))) {
for (BlobInfo metadata : diffFiles) {
logger.atInfo().log("Restoring: %s", metadata.getName());
try (InputStream input = gcsUtils.openInputStream(metadata.getBlobId())) {
PeekingIterator<ImmutableObject> commitLogs =
peekingIterator(createDeserializingIterator(input));
peekingIterator(createDeserializingIterator(input, true));
lastCheckpoint = (CommitLogCheckpoint) commitLogs.next();
saveOfy(ImmutableList.of(lastCheckpoint)); // Save the checkpoint itself.
while (commitLogs.hasNext()) {

View File

@@ -17,8 +17,8 @@ package google.registry.batch;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
import static google.registry.flows.FlowUtils.marshalWithLenientRetry;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.ResourceUtils.readResourceUtf8;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -36,6 +36,7 @@ import google.registry.flows.StatelessRequestSessionMetadata;
import google.registry.model.domain.DomainBase;
import google.registry.model.eppcommon.ProtocolDefinition;
import google.registry.model.eppoutput.EppOutput;
import google.registry.persistence.transaction.QueryComposer.Comparator;
import google.registry.request.Action;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
@@ -128,12 +129,15 @@ public class DeleteExpiredDomainsAction implements Runnable {
logger.atInfo().log(
"Deleting non-renewing domains with autorenew end times up through %s.", runTime);
// Note: This query is (and must be) non-transactional, and thus, is only eventually consistent.
// Note: in Datastore, this query is (and must be) non-transactional, and thus, is only
// eventually consistent.
ImmutableList<DomainBase> domainsToDelete =
ofy().load().type(DomainBase.class).filter("autorenewEndTime <=", runTime).list().stream()
// Datastore can't do two inequalities in one query, so the second happens in-memory.
.filter(d -> d.getDeletionTime().isEqual(END_OF_TIME))
.collect(toImmutableList());
transactIfJpaTm(
() ->
tm().createQueryComposer(DomainBase.class)
.where("autorenewEndTime", Comparator.LTE, runTime)
.where("deletionTime", Comparator.EQ, END_OF_TIME)
.list());
if (domainsToDelete.isEmpty()) {
logger.atInfo().log("Found 0 domains to delete.");
response.setPayload("Found 0 domains to delete.");

View File

@@ -15,12 +15,14 @@
package google.registry.batch;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.config.RegistryEnvironment.PRODUCTION;
import static google.registry.mapreduce.MapreduceRunner.PARAM_DRY_RUN;
import static google.registry.mapreduce.inputs.EppResourceInputs.createEntityInput;
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import com.google.appengine.tools.mapreduce.Mapper;
import com.google.common.collect.ImmutableList;
@@ -28,16 +30,24 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryEnvironment;
import google.registry.flows.poll.PollFlowUtils;
import google.registry.mapreduce.MapreduceRunner;
import google.registry.model.EppResource;
import google.registry.model.EppResourceUtils;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntryDao;
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 javax.inject.Inject;
@@ -46,8 +56,8 @@ import javax.inject.Inject;
* the associated ForeignKey and EppResourceIndex entities.
*
* <p>This only deletes contacts and hosts, NOT domains. To delete domains, use {@link
* DeleteLoadTestDataAction} and pass it the TLD(s) that the load test domains were created on. Note
* that DeleteLoadTestDataAction is safe enough to run in production whereas this mapreduce is not,
* DeleteProberDataAction} and pass it the TLD(s) that the load test domains were created on. Note
* that DeleteProberDataAction is safe enough to run in production whereas this mapreduce is not,
* but this one does not need to be runnable in production because load testing isn't run against
* production.
*/
@@ -68,15 +78,22 @@ public class DeleteLoadTestDataAction implements Runnable {
*/
private static final ImmutableSet<String> LOAD_TEST_REGISTRARS = ImmutableSet.of("proxy");
@Inject
@Parameter(PARAM_DRY_RUN)
boolean isDryRun;
@Inject MapreduceRunner mrRunner;
@Inject Response response;
private final boolean isDryRun;
private final MapreduceRunner mrRunner;
private final Response response;
private final Clock clock;
@Inject
DeleteLoadTestDataAction() {}
DeleteLoadTestDataAction(
@Parameter(PARAM_DRY_RUN) boolean isDryRun,
MapreduceRunner mrRunner,
Response response,
Clock clock) {
this.isDryRun = isDryRun;
this.mrRunner = mrRunner;
this.response = response;
this.clock = clock;
}
@Override
public void run() {
@@ -87,14 +104,85 @@ public class DeleteLoadTestDataAction implements Runnable {
!RegistryEnvironment.get().equals(PRODUCTION),
"This mapreduce is not safe to run on PRODUCTION.");
mrRunner
.setJobName("Delete load test data")
.setModuleName("backend")
.runMapOnly(
new DeleteLoadTestDataMapper(isDryRun),
ImmutableList.of(
createEntityInput(ContactResource.class), createEntityInput(HostResource.class)))
.sendLinkToMapreduceConsole(response);
if (tm().isOfy()) {
mrRunner
.setJobName("Delete load test data")
.setModuleName("backend")
.runMapOnly(
new DeleteLoadTestDataMapper(isDryRun),
ImmutableList.of(
createEntityInput(ContactResource.class), createEntityInput(HostResource.class)))
.sendLinkToMapreduceConsole(response);
} else {
tm().transact(
() -> {
LOAD_TEST_REGISTRARS.forEach(this::deletePollMessages);
tm().loadAllOfStream(ContactResource.class).forEach(this::deleteContact);
tm().loadAllOfStream(HostResource.class).forEach(this::deleteHost);
});
}
}
private void deletePollMessages(String registrarId) {
ImmutableList<PollMessage> pollMessages =
PollFlowUtils.createPollMessageQuery(registrarId, END_OF_TIME).list();
if (isDryRun) {
logger.atInfo().log(
"Would delete %d poll messages for registrar %s.", pollMessages.size(), registrarId);
} else {
pollMessages.forEach(tm()::delete);
}
}
private void deleteContact(ContactResource contact) {
if (!LOAD_TEST_REGISTRARS.contains(contact.getPersistedCurrentSponsorClientId())) {
return;
}
// We cannot remove contacts from domains in the general case, so we cannot delete contacts
// that are linked to domains (since it would break the foreign keys)
if (EppResourceUtils.isLinked(contact.createVKey(), clock.nowUtc())) {
logger.atWarning().log(
"Cannot delete contact with repo ID %s since it is referenced from a domain",
contact.getRepoId());
return;
}
deleteResource(contact);
}
private void deleteHost(HostResource host) {
if (!LOAD_TEST_REGISTRARS.contains(host.getPersistedCurrentSponsorClientId())) {
return;
}
VKey<HostResource> hostVKey = host.createVKey();
// We can remove hosts from linked domains, so we should do so then delete the hosts
ImmutableSet<VKey<DomainBase>> linkedDomains =
EppResourceUtils.getLinkedDomainKeys(hostVKey, clock.nowUtc(), null);
tm().loadByKeys(linkedDomains)
.values()
.forEach(
domain -> {
ImmutableSet<VKey<HostResource>> remainingHosts =
domain.getNsHosts().stream()
.filter(vkey -> !vkey.equals(hostVKey))
.collect(toImmutableSet());
tm().put(domain.asBuilder().setNameservers(remainingHosts).build());
});
deleteResource(host);
}
private void deleteResource(EppResource eppResource) {
// In SQL, the only objects parented on the resource are poll messages (deleted above) and
// history objects.
ImmutableList<HistoryEntry> historyObjects =
HistoryEntryDao.loadHistoryObjectsForResource(eppResource.createVKey());
if (isDryRun) {
logger.atInfo().log(
"Would delete repo ID %s along with %d history objects",
eppResource.getRepoId(), historyObjects.size());
} else {
historyObjects.forEach(tm()::delete);
tm().delete(eppResource);
}
}
/** Provides the map method that runs for each existing contact and host entity. */

View File

@@ -21,9 +21,12 @@ import static google.registry.mapreduce.MapreduceRunner.PARAM_DRY_RUN;
import static google.registry.mapreduce.inputs.EppResourceInputs.createChildEntityInput;
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
import static google.registry.model.domain.Period.Unit.YEARS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
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.jpaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
import static google.registry.util.CollectionUtils.union;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
@@ -38,10 +41,8 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Range;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.googlecode.objectify.Key;
import google.registry.mapreduce.MapreduceRunner;
import google.registry.mapreduce.inputs.NullInput;
import google.registry.model.EppResource;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
@@ -54,7 +55,7 @@ import google.registry.model.domain.Period;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.request.Action;
import google.registry.request.Parameter;
import google.registry.request.Response;
@@ -92,31 +93,88 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
@Override
public void run() {
Cursor cursor =
tm().loadByKeyIfPresent(Cursor.createGlobalVKey(RECURRING_BILLING)).orElse(null);
DateTime executeTime = clock.nowUtc();
DateTime persistedCursorTime = (cursor == null ? START_OF_TIME : cursor.getCursorTime());
DateTime persistedCursorTime =
transactIfJpaTm(
() ->
tm().loadByKeyIfPresent(Cursor.createGlobalVKey(RECURRING_BILLING))
.orElse(Cursor.createGlobal(RECURRING_BILLING, START_OF_TIME))
.getCursorTime());
DateTime cursorTime = cursorTimeParam.orElse(persistedCursorTime);
checkArgument(
cursorTime.isBefore(executeTime),
"Cursor time must be earlier than execution time.");
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);
mrRunner
.setJobName("Expand Recurring billing events into synthetic OneTime events.")
.setModuleName("backend")
.runMapreduce(
new ExpandRecurringBillingEventsMapper(isDryRun, cursorTime, clock.nowUtc()),
new ExpandRecurringBillingEventsReducer(isDryRun, persistedCursorTime),
// Add an extra shard that maps over a null recurring event (see the mapper for why).
ImmutableList.of(
new NullInput<>(),
createChildEntityInput(
ImmutableSet.of(DomainBase.class), ImmutableSet.of(Recurring.class))))
.sendLinkToMapreduceConsole(response);
}
if (tm().isOfy()) {
mrRunner
.setJobName("Expand Recurring billing events into synthetic OneTime events.")
.setModuleName("backend")
.runMapreduce(
new ExpandRecurringBillingEventsMapper(isDryRun, cursorTime, clock.nowUtc()),
new ExpandRecurringBillingEventsReducer(isDryRun, persistedCursorTime),
// Add an extra shard that maps over a null recurring event (see the mapper for why).
ImmutableList.of(
new NullInput<>(),
createChildEntityInput(
ImmutableSet.of(DomainBase.class), ImmutableSet.of(Recurring.class))))
.sendLinkToMapreduceConsole(response);
} else {
int numBillingEventsSaved =
jpaTm()
.transact(
() ->
jpaTm()
.query(
"FROM BillingRecurrence "
+ "WHERE eventTime <= :executeTime "
+ "AND eventTime < recurrenceEndTime "
+ "ORDER BY id ASC",
Recurring.class)
.setParameter("executeTime", executeTime)
// Need to get a list from the transaction and then convert it to a stream
// for further processing. If we get a stream directly, each elements gets
// processed downstream eagerly but Hibernate returns a
// ScrollableResultsIterator that cannot be advanced outside the
// transaction, resulting in an exception.
.getResultList())
.stream()
.map(
recurring ->
jpaTm()
.transact(
() ->
expandBillingEvent(recurring, executeTime, cursorTime, isDryRun)))
.reduce(0, Integer::sum);
if (!isDryRun) {
logger.atInfo().log("Saved OneTime billing events", numBillingEventsSaved);
} else {
logger.atInfo().log("Generated OneTime billing events (dry run)", numBillingEventsSaved);
}
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(
String.format(
"Current cursor position %s does not match persisted cursor position %s.",
currentCursorTime, persistedCursorTime));
}
if (!isDryRun) {
tm().put(Cursor.createGlobal(RECURRING_BILLING, executeTime));
}
});
}
}
/** Mapper to expand {@link Recurring} billing events into synthetic {@link OneTime} events. */
public static class ExpandRecurringBillingEventsMapper
extends Mapper<Recurring, DateTime, DateTime> {
@@ -155,100 +213,7 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
try {
numBillingEventsSaved =
tm().transactNew(
() -> {
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 mapreduce).
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);
Key<? extends EppResource> domainKey = recurring.getParentKey().getParent();
Iterable<OneTime> oneTimesForDomain =
ofy().load().type(OneTime.class).ancestor(domainKey);
// Determine the billing times that already have OneTime events persisted.
ImmutableSet<DateTime> existingBillingTimes =
getExistingBillingTimes(oneTimesForDomain, recurring);
ImmutableSet.Builder<HistoryEntry> 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)
.setClientId(recurring.getClientId())
.setModificationTime(tm().getTransactionTime())
// TODO (jianglai): modify this to use setDomain instead when
// converting this action to be SQL-aware.
.setDomainRepoId(domainKey.getName())
.setPeriod(Period.create(1, YEARS))
.setReason(
"Domain autorenewal by ExpandRecurringBillingEventsAction")
.setRequestedByRegistrar(false)
.setType(DOMAIN_AUTORENEW)
// 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());
// Determine the cost for a one-year renewal.
Money renewCost = getDomainRenewCost(recurring.getTargetId(), eventTime, 1);
syntheticOneTimesBuilder.add(
new OneTime.Builder()
.setBillingTime(billingTime)
.setClientId(recurring.getClientId())
.setCost(renewCost)
.setEventTime(eventTime)
.setFlags(union(recurring.getFlags(), Flag.SYNTHETIC))
.setParent(historyEntry)
.setPeriodYears(1)
.setReason(recurring.getReason())
.setSyntheticCreationTime(executeTime)
.setCancellationMatchingBillingEvent(recurring.createVKey())
.setTargetId(recurring.getTargetId())
.build());
}
Set<HistoryEntry> historyEntries = historyEntriesBuilder.build();
Set<OneTime> syntheticOneTimes = syntheticOneTimesBuilder.build();
if (!isDryRun) {
ImmutableSet<ImmutableObject> entitiesToSave =
new ImmutableSet.Builder<ImmutableObject>()
.addAll(historyEntries)
.addAll(syntheticOneTimes)
.build();
ofy().save().entities(entitiesToSave).now();
}
return syntheticOneTimes.size();
});
() -> expandBillingEvent(recurring, executeTime, cursorTime, isDryRun));
} catch (Throwable t) {
getContext().incrementCounter("error: " + t.getClass().getSimpleName());
getContext().incrementCounter(ERROR_COUNTER);
@@ -260,45 +225,12 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
if (!isDryRun) {
getContext().incrementCounter("Saved OneTime billing events", numBillingEventsSaved);
} else {
getContext().incrementCounter(
"Generated OneTime billing events (dry run)", numBillingEventsSaved);
getContext()
.incrementCounter("Generated OneTime billing events (dry run)", numBillingEventsSaved);
}
}
/**
* Filters a set of {@link DateTime}s down to event times that are in scope for a particular
* mapreduce run, given the cursor time and the mapreduce execution time.
*/
private 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 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());
}
}
/**
* "Reducer" to advance the cursor after all map jobs have been completed. The NullInput into the
* mapper will cause the mapper to emit one timestamp pair (current cursor and execution time),
@@ -331,7 +263,8 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
isDryRun ? "(dry run) " : "", cursorTime, executionTime);
tm().transact(
() -> {
Cursor cursor = ofy().load().key(Cursor.createGlobalKey(RECURRING_BILLING)).now();
Cursor cursor =
auditedOfy().load().key(Cursor.createGlobalKey(RECURRING_BILLING)).now();
DateTime currentCursorTime =
(cursor == null ? START_OF_TIME : cursor.getCursorTime());
if (!currentCursorTime.equals(expectedPersistedCursorTime)) {
@@ -346,4 +279,135 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
});
}
}
private static int expandBillingEvent(
Recurring recurring, DateTime executeTime, DateTime cursorTime, boolean isDryRun) {
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 mapreduce).
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<DomainBase> domainKey =
VKey.create(
DomainBase.class, recurring.getDomainRepoId(), recurring.getParentKey().getParent());
Iterable<OneTime> oneTimesForDomain;
if (tm().isOfy()) {
oneTimesForDomain = auditedOfy().load().type(OneTime.class).ancestor(domainKey.getOfyKey());
} else {
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)
.setClientId(recurring.getClientId())
.setModificationTime(tm().getTransactionTime())
.setDomain(tm().loadByKey(domainKey))
.setPeriod(Period.create(1, YEARS))
.setReason("Domain autorenewal by ExpandRecurringBillingEventsAction")
.setRequestedByRegistrar(false)
.setType(DOMAIN_AUTORENEW)
// 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());
// Determine the cost for a one-year renewal.
Money renewCost = getDomainRenewCost(recurring.getTargetId(), eventTime, 1);
syntheticOneTimesBuilder.add(
new OneTime.Builder()
.setBillingTime(billingTime)
.setClientId(recurring.getClientId())
.setCost(renewCost)
.setEventTime(eventTime)
.setFlags(union(recurring.getFlags(), Flag.SYNTHETIC))
.setParent(historyEntry)
.setPeriodYears(1)
.setReason(recurring.getReason())
.setSyntheticCreationTime(executeTime)
.setCancellationMatchingBillingEvent(recurring.createVKey())
.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
* mapreduce run, given the cursor time and the mapreduce 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());
}
}

View File

@@ -23,6 +23,7 @@ import static google.registry.batch.AsyncTaskEnqueuer.PARAM_REQUESTED_TIME;
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_HOST_RENAME;
import static google.registry.batch.AsyncTaskMetrics.OperationType.DNS_REFRESH;
import static google.registry.mapreduce.inputs.EppResourceInputs.createEntityInput;
import static google.registry.model.EppResourceUtils.getLinkedDomainKeys;
import static google.registry.model.EppResourceUtils.isActive;
import static google.registry.model.EppResourceUtils.isDeleted;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
@@ -69,6 +70,7 @@ import java.util.logging.Level;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.http.HttpStatus;
import org.joda.time.DateTime;
import org.joda.time.Duration;
@@ -86,6 +88,8 @@ public class RefreshDnsOnHostRenameAction implements Runnable {
@Inject Clock clock;
@Inject MapreduceRunner mrRunner;
@Inject @Named(QUEUE_ASYNC_HOST_RENAME) Queue pullQueue;
@Inject DnsQueue dnsQueue;
@Inject RequestStatusChecker requestStatusChecker;
@Inject Response response;
@Inject Retrier retrier;
@@ -153,7 +157,39 @@ public class RefreshDnsOnHostRenameAction implements Runnable {
} else {
logger.atInfo().log(
"Processing asynchronous DNS refresh for renamed hosts: %s", hostKeys.build());
runMapreduce(refreshRequests, lock);
if (tm().isOfy()) {
runMapreduce(refreshRequests, lock);
} else {
try {
refreshRequests.stream()
.flatMap(
request ->
getLinkedDomainKeys(request.hostKey(), request.lastUpdateTime(), null)
.stream())
.distinct()
.map(domainKey -> tm().transact(() -> tm().loadByKey(domainKey).getDomainName()))
.forEach(
domainName -> {
retrier.callWithRetry(
() -> dnsQueue.addDomainRefreshTask(domainName),
TransientFailureException.class);
logger.atInfo().log("Enqueued DNS refresh for domain %s.", domainName);
});
deleteTasksWithRetry(
refreshRequests,
getQueue(QUEUE_ASYNC_HOST_RENAME),
asyncTaskMetrics,
retrier,
OperationResult.SUCCESS);
} catch (Throwable t) {
String message = "Error refreshing DNS on host rename.";
logger.atSevere().withCause(t).log(message);
response.setPayload(message);
response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
} finally {
lock.get().release();
}
}
}
}

View File

@@ -54,6 +54,8 @@ import javax.inject.Inject;
service = Action.Service.BACKEND,
path = "/_dr/task/resaveAllEppResources",
auth = Auth.AUTH_INTERNAL_OR_ADMIN)
// No longer needed in SQL. Subject to future removal.
@Deprecated
public class ResaveAllEppResourcesAction implements Runnable {
@Inject MapreduceRunner mrRunner;

View File

@@ -18,17 +18,23 @@ import static com.google.common.base.Verify.verify;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import google.registry.backup.AppEngineEnvironment;
import google.registry.model.contact.ContactResource;
import google.registry.persistence.transaction.CriteriaQueryBuilder;
import google.registry.persistence.transaction.JpaTransactionManager;
import java.io.Serializable;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.metrics.Counter;
import org.apache.beam.sdk.metrics.Metrics;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.transforms.Create;
import org.apache.beam.sdk.transforms.DoFn;
import org.apache.beam.sdk.transforms.ParDo;
/** Toy pipeline that demonstrates how to use {@link JpaTransactionManager} in BEAM pipelines. */
/**
* Toy pipeline that demonstrates how to use {@link JpaTransactionManager} in BEAM pipelines.
*
* <p>This pipeline may also be used as an integration test for {@link RegistryJpaIO.Read} in a
* project with realistic data.
*/
public class JpaDemoPipeline implements Serializable {
public static void main(String[] args) {
@@ -38,23 +44,16 @@ public class JpaDemoPipeline implements Serializable {
Pipeline pipeline = Pipeline.create(options);
pipeline
.apply("Start", Create.of((Void) null))
.apply(
"Generate Elements",
ParDo.of(
new DoFn<Void, Void>() {
@ProcessElement
public void processElement(OutputReceiver<Void> output) {
for (int i = 0; i < 500; i++) {
output.output(null);
}
}
}))
"Read contacts",
RegistryJpaIO.read(
() -> CriteriaQueryBuilder.create(ContactResource.class).build(),
ContactResource::getRepoId))
.apply(
"Make Query",
"Count Contacts",
ParDo.of(
new DoFn<Void, Void>() {
private Counter counter = Metrics.counter("Demo", "Read");
new DoFn<String, Void>() {
private Counter counter = Metrics.counter("Contacts", "Read");
@ProcessElement
public void processElement() {

View File

@@ -21,14 +21,15 @@ import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import google.registry.backup.AppEngineEnvironment;
import google.registry.beam.common.RegistryQuery.QueryComposerFactory;
import google.registry.beam.common.RegistryQuery.RegistryQueryFactory;
import google.registry.beam.common.RegistryQuery.CriteriaQuerySupplier;
import google.registry.model.ofy.ObjectifyService;
import google.registry.persistence.transaction.JpaTransactionManager;
import google.registry.persistence.transaction.TransactionManagerFactory;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nullable;
import javax.persistence.criteria.CriteriaQuery;
import org.apache.beam.sdk.coders.Coder;
import org.apache.beam.sdk.coders.SerializableCoder;
@@ -60,13 +61,18 @@ public final class RegistryJpaIO {
private RegistryJpaIO() {}
public static <R> Read<R, R> read(QueryComposerFactory<R> queryFactory) {
return Read.<R, R>builder().queryFactory(queryFactory).build();
public static <R> Read<R, R> read(CriteriaQuerySupplier<R> query) {
return read(query, x -> x);
}
public static <R, T> Read<R, T> read(
QueryComposerFactory<R> queryFactory, SerializableFunction<R, T> resultMapper) {
return Read.<R, T>builder().queryFactory(queryFactory).resultMapper(resultMapper).build();
CriteriaQuerySupplier<R> query, SerializableFunction<R, T> resultMapper) {
return Read.<R, T>builder().criteriaQuery(query).resultMapper(resultMapper).build();
}
public static <R, T> Read<R, T> read(
String sql, boolean nativeQuery, SerializableFunction<R, T> resultMapper) {
return read(sql, null, nativeQuery, resultMapper);
}
/**
@@ -74,8 +80,39 @@ public final class RegistryJpaIO {
*
* <p>User should take care to prevent sql-injection attacks.
*/
public static <R, T> Read<R, T> read(String jpql, SerializableFunction<R, T> resultMapper) {
return Read.<R, T>builder().jpqlQueryFactory(jpql).resultMapper(resultMapper).build();
public static <R, T> Read<R, T> read(
String sql,
@Nullable Map<String, Object> parameter,
boolean nativeQuery,
SerializableFunction<R, T> resultMapper) {
Read.Builder<R, T> builder = Read.builder();
if (nativeQuery) {
builder.nativeQuery(sql, parameter);
} else {
builder.jpqlQuery(sql, parameter);
}
return builder.resultMapper(resultMapper).build();
}
public static <R, T> Read<R, T> read(
String jpql, Class<R> clazz, SerializableFunction<R, T> resultMapper) {
return read(jpql, null, clazz, resultMapper);
}
/**
* Returns a {@link Read} connector based on the given {@code jpql} typed query string.
*
* <p>User should take care to prevent sql-injection attacks.
*/
public static <R, T> Read<R, T> read(
String jpql,
@Nullable Map<String, Object> parameter,
Class<R> clazz,
SerializableFunction<R, T> resultMapper) {
return Read.<R, T>builder()
.jpqlQuery(jpql, clazz, parameter)
.resultMapper(resultMapper)
.build();
}
public static <T> Write<T> write() {
@@ -94,7 +131,7 @@ public final class RegistryJpaIO {
abstract String name();
abstract RegistryQueryFactory<R> queryFactory();
abstract RegistryQuery<R> query();
abstract SerializableFunction<R, T> resultMapper();
@@ -107,9 +144,7 @@ public final class RegistryJpaIO {
public PCollection<T> expand(PBegin input) {
return input
.apply("Starting " + name(), Create.of((Void) null))
.apply(
"Run query for " + name(),
ParDo.of(new QueryRunner<>(queryFactory(), resultMapper())))
.apply("Run query for " + name(), ParDo.of(new QueryRunner<>(query(), resultMapper())))
.setCoder(coder())
.apply("Reshuffle", Reshuffle.viaRandomKey());
}
@@ -127,9 +162,8 @@ public final class RegistryJpaIO {
}
static <R, T> Builder<R, T> builder() {
return new AutoValue_RegistryJpaIO_Read.Builder()
return new AutoValue_RegistryJpaIO_Read.Builder<R, T>()
.name(DEFAULT_NAME)
.resultMapper(x -> x)
.coder(SerializableCoder.of(Serializable.class));
}
@@ -138,7 +172,7 @@ public final class RegistryJpaIO {
abstract Builder<R, T> name(String name);
abstract Builder<R, T> queryFactory(RegistryQueryFactory<R> queryFactory);
abstract Builder<R, T> query(RegistryQuery<R> query);
abstract Builder<R, T> resultMapper(SerializableFunction<R, T> mapper);
@@ -146,21 +180,29 @@ public final class RegistryJpaIO {
abstract Read<R, T> build();
Builder<R, T> queryFactory(QueryComposerFactory<R> queryFactory) {
return queryFactory(RegistryQuery.createQueryFactory(queryFactory));
Builder<R, T> criteriaQuery(CriteriaQuerySupplier<R> criteriaQuery) {
return query(RegistryQuery.createQuery(criteriaQuery));
}
Builder<R, T> jpqlQueryFactory(String jpql) {
return queryFactory(RegistryQuery.createQueryFactory(jpql));
Builder<R, T> nativeQuery(String sql, Map<String, Object> parameters) {
return query(RegistryQuery.createQuery(sql, parameters, true));
}
Builder<R, T> jpqlQuery(String jpql, Map<String, Object> parameters) {
return query(RegistryQuery.createQuery(jpql, parameters, false));
}
Builder<R, T> jpqlQuery(String jpql, Class<R> clazz, Map<String, Object> parameters) {
return query(RegistryQuery.createQuery(jpql, parameters, clazz));
}
}
static class QueryRunner<R, T> extends DoFn<Void, T> {
private final RegistryQueryFactory<R> queryFactory;
private final RegistryQuery<R> query;
private final SerializableFunction<R, T> resultMapper;
QueryRunner(RegistryQueryFactory<R> queryFactory, SerializableFunction<R, T> resultMapper) {
this.queryFactory = queryFactory;
QueryRunner(RegistryQuery<R> query, SerializableFunction<R, T> resultMapper) {
this.query = query;
this.resultMapper = resultMapper;
}
@@ -172,10 +214,7 @@ public final class RegistryJpaIO {
// TODO(b/187210388): JpaTransactionManager should support non-transactional query.
jpaTm()
.transactNoRetry(
() ->
queryFactory.apply(jpaTm()).stream()
.map(resultMapper::apply)
.forEach(outputReceiver::output));
() -> query.stream().map(resultMapper::apply).forEach(outputReceiver::output));
}
}
}

View File

@@ -14,48 +14,75 @@
package google.registry.beam.common;
import google.registry.persistence.transaction.JpaTransactionManager;
import google.registry.persistence.transaction.QueryComposer;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.beam.sdk.transforms.SerializableFunction;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
/** Interface for query instances used by {@link RegistryJpaIO.Read}. */
public interface RegistryQuery<T> {
public interface RegistryQuery<T> extends Serializable {
Stream<T> stream();
/** Factory for {@link RegistryQuery}. */
interface RegistryQueryFactory<T>
extends SerializableFunction<JpaTransactionManager, RegistryQuery<T>> {}
// TODO(mmuller): Consider detached JpaQueryComposer that works with any JpaTransactionManager
// instance, i.e., change composer.buildQuery() to composer.buildQuery(JpaTransactionManager).
// This way QueryComposer becomes reusable and serializable (at least with Hibernate), and this
// interface would no longer be necessary.
interface QueryComposerFactory<T>
extends SerializableFunction<JpaTransactionManager, QueryComposer<T>> {}
interface CriteriaQuerySupplier<T> extends Supplier<CriteriaQuery<T>>, Serializable {}
/**
* Returns a {@link RegistryQueryFactory} that creates a JPQL query from constant text.
* Returns a {@link RegistryQuery} that creates a string query from constant text.
*
* @param nativeQuery whether the given string is to be interpreted as a native query or JPQL.
* @param parameters parameters to be substituted in the query.
* @param <T> Type of each row in the result set, {@link Object} in single-select queries, and
* {@code Object[]} in multi-select queries.
*/
@SuppressWarnings("unchecked") // query.getResultStream: jpa api uses raw type
static <T> RegistryQueryFactory<T> createQueryFactory(String jpql) {
return (JpaTransactionManager jpa) ->
() -> {
EntityManager entityManager = jpa.getEntityManager();
Query query = entityManager.createQuery(jpql);
return query.getResultStream().map(e -> detach(entityManager, e));
};
static <T> RegistryQuery<T> createQuery(
String sql, @Nullable Map<String, Object> parameters, boolean nativeQuery) {
return () -> {
EntityManager entityManager = jpaTm().getEntityManager();
Query query =
nativeQuery ? entityManager.createNativeQuery(sql) : entityManager.createQuery(sql);
if (parameters != null) {
parameters.forEach(query::setParameter);
}
@SuppressWarnings("unchecked")
Stream<T> resultStream = query.getResultStream();
return nativeQuery ? resultStream : resultStream.map(e -> detach(entityManager, e));
};
}
static <T> RegistryQueryFactory<T> createQueryFactory(
QueryComposerFactory<T> queryComposerFactory) {
return (JpaTransactionManager jpa) ->
() -> queryComposerFactory.apply(jpa).withAutoDetachOnLoad(true).stream();
/**
* Returns a {@link RegistryQuery} that creates a typed JPQL query from constant text.
*
* @param parameters parameters to be substituted in the query.
* @param <T> Type of each row in the result set.
*/
static <T> RegistryQuery<T> createQuery(
String jpql, @Nullable Map<String, Object> parameters, Class<T> clazz) {
return () -> {
TypedQuery<T> query = jpaTm().query(jpql, clazz);
if (parameters != null) {
parameters.forEach(query::setParameter);
}
return query.getResultStream();
};
}
/**
* Returns a {@link RegistryQuery} from a {@link CriteriaQuery} supplier.
*
* <p>A serializable supplier is needed in because {@link CriteriaQuery} itself must be created
* within a transaction, and we are not in a transaction yet when this function is called to set
* up the pipeline.
*
* @param <T> Type of each row in the result set.
*/
static <T> RegistryQuery<T> createQuery(CriteriaQuerySupplier<T> criteriaQuery) {
return () -> jpaTm().query(criteriaQuery.get()).getResultStream();
}
/**

View File

@@ -251,7 +251,14 @@ public abstract class BillingEvent implements Serializable {
InvoiceGroupingKey getInvoiceGroupingKey() {
return new AutoValue_BillingEvent_InvoiceGroupingKey(
billingTime().toLocalDate().withDayOfMonth(1).toString(),
billingTime().toLocalDate().withDayOfMonth(1).plusYears(years()).minusDays(1).toString(),
years() == 0
? ""
: billingTime()
.toLocalDate()
.withDayOfMonth(1)
.plusYears(years())
.minusDays(1)
.toString(),
billingId(),
String.format("%s - %s", registrarId(), tld()),
String.format("%s | TLD: %s | TERM: %d-year", action(), tld(), years()),

View File

@@ -0,0 +1,260 @@
// Copyright 2021 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.beam.rde;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.model.EppResourceUtils.loadAtPointInTimeAsync;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.BaseEncoding;
import google.registry.beam.common.RegistryJpaIO;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource;
import google.registry.model.rde.RdeMode;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.Registrar.Type;
import google.registry.persistence.VKey;
import google.registry.rde.DepositFragment;
import google.registry.rde.PendingDeposit;
import google.registry.rde.PendingDeposit.PendingDepositCoder;
import google.registry.rde.RdeFragmenter;
import google.registry.rde.RdeMarshaller;
import google.registry.xml.ValidationMode;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import javax.persistence.Entity;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.PipelineResult;
import org.apache.beam.sdk.coders.KvCoder;
import org.apache.beam.sdk.coders.SerializableCoder;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.transforms.FlatMapElements;
import org.apache.beam.sdk.transforms.Flatten;
import org.apache.beam.sdk.transforms.Reshuffle;
import org.apache.beam.sdk.values.KV;
import org.apache.beam.sdk.values.PCollection;
import org.apache.beam.sdk.values.PCollectionList;
import org.apache.beam.sdk.values.TypeDescriptor;
import org.apache.beam.sdk.values.TypeDescriptors;
import org.joda.time.DateTime;
/**
* Definition of a Dataflow Flex template, which generates RDE/BRDA deposits.
*
* <p>To stage this template locally, run the {@code stage_beam_pipeline.sh} shell script.
*
* <p>Then, you can run the staged template via the API client library, gCloud or a raw REST call.
*
* @see <a href="https://cloud.google.com/dataflow/docs/guides/templates/using-flex-templates">Using
* Flex Templates</a>
*/
public class RdePipeline implements Serializable {
private final RdeMarshaller marshaller;
private final ImmutableSetMultimap<String, PendingDeposit> pendings;
// Registrars to be excluded from data escrow. Not including the sandbox-only OTE type so that
// if sneaks into production we would get an extra signal.
private static final ImmutableSet<Type> IGNORED_REGISTRAR_TYPES =
Sets.immutableEnumSet(Registrar.Type.MONITORING, Registrar.Type.TEST);
private static final String EPP_RESOURCE_QUERY =
"SELECT id FROM %entity% "
+ "WHERE COALESCE(creationClientId, '') NOT LIKE 'prober-%' "
+ "AND COALESCE(currentSponsorClientId, '') NOT LIKE 'prober-%' "
+ "AND COALESCE(lastEppUpdateClientId, '') NOT LIKE 'prober-%'";
public static String createEppResourceQuery(Class<? extends EppResource> clazz) {
return EPP_RESOURCE_QUERY.replace("%entity%", clazz.getAnnotation(Entity.class).name())
+ (clazz.equals(DomainBase.class) ? " AND tld in (:tlds)" : "");
}
RdePipeline(RdePipelineOptions options) throws IOException, ClassNotFoundException {
this.marshaller = new RdeMarshaller(ValidationMode.valueOf(options.getValidationMode()));
this.pendings = decodePendings(options.getPendings());
}
@VisibleForTesting
PipelineResult run(Pipeline pipeline) {
createFragments(pipeline);
return pipeline.run();
}
PipelineResult run() {
return run(Pipeline.create());
}
PCollection<KV<PendingDeposit, DepositFragment>> createFragments(Pipeline pipeline) {
PCollection<KV<PendingDeposit, DepositFragment>> fragments =
PCollectionList.of(processRegistrars(pipeline))
.and(processNonRegistrarEntities(pipeline, DomainBase.class))
.and(processNonRegistrarEntities(pipeline, ContactResource.class))
.and(processNonRegistrarEntities(pipeline, HostResource.class))
.apply(Flatten.pCollections())
.setCoder(
KvCoder.of(PendingDepositCoder.of(), SerializableCoder.of(DepositFragment.class)));
return fragments;
}
PCollection<KV<PendingDeposit, DepositFragment>> processRegistrars(Pipeline pipeline) {
return pipeline
.apply(
"Read all production Registrar entities",
RegistryJpaIO.read(
"SELECT clientIdentifier FROM Registrar WHERE type NOT IN (:types)",
ImmutableMap.of("types", IGNORED_REGISTRAR_TYPES),
String.class,
// TODO: consider adding coders for entities and pass them directly instead of using
// VKeys.
id -> VKey.createSql(Registrar.class, id)))
.apply(
"Marshal Registrar into DepositFragment",
FlatMapElements.into(
TypeDescriptors.kvs(
TypeDescriptor.of(PendingDeposit.class),
TypeDescriptor.of(DepositFragment.class)))
.via(
(VKey<Registrar> key) -> {
Registrar registrar = jpaTm().transact(() -> jpaTm().loadByKey(key));
DepositFragment fragment = marshaller.marshalRegistrar(registrar);
return pendings.values().stream()
.map(pending -> KV.of(pending, fragment))
.collect(toImmutableSet());
}));
}
@SuppressWarnings("deprecation") // Reshuffle is still recommended by Dataflow.
<T extends EppResource>
PCollection<KV<PendingDeposit, DepositFragment>> processNonRegistrarEntities(
Pipeline pipeline, Class<T> clazz) {
return createInputs(pipeline, clazz)
.apply("Marshal " + clazz.getSimpleName() + " into DepositFragment", mapToFragments(clazz))
.setCoder(KvCoder.of(PendingDepositCoder.of(), SerializableCoder.of(DepositFragment.class)))
.apply(
"Reshuffle KV<PendingDeposit, DepositFragment> of "
+ clazz.getSimpleName()
+ " to prevent fusion",
Reshuffle.of());
}
<T extends EppResource> PCollection<VKey<T>> createInputs(Pipeline pipeline, Class<T> clazz) {
return pipeline.apply(
"Read all production " + clazz.getSimpleName() + " entities",
RegistryJpaIO.read(
createEppResourceQuery(clazz),
clazz.equals(DomainBase.class)
? ImmutableMap.of("tlds", pendings.keySet())
: ImmutableMap.of(),
String.class,
// TODO: consider adding coders for entities and pass them directly instead of using
// VKeys.
x -> VKey.create(clazz, x)));
}
<T extends EppResource>
FlatMapElements<VKey<T>, KV<PendingDeposit, DepositFragment>> mapToFragments(Class<T> clazz) {
return FlatMapElements.into(
TypeDescriptors.kvs(
TypeDescriptor.of(PendingDeposit.class), TypeDescriptor.of(DepositFragment.class)))
.via(
(VKey<T> key) -> {
T resource = jpaTm().transact(() -> jpaTm().loadByKey(key));
// The set of all TLDs to which this resource should be emitted.
ImmutableSet<String> tlds =
clazz.equals(DomainBase.class)
? ImmutableSet.of(((DomainBase) resource).getTld())
: pendings.keySet();
// Get the set of all point-in-time watermarks we need, to minimize rewinding.
ImmutableSet<DateTime> dates =
tlds.stream()
.map(pendings::get)
.flatMap(ImmutableSet::stream)
.map(PendingDeposit::watermark)
.collect(toImmutableSet());
// Launch asynchronous fetches of point-in-time representations of resource.
ImmutableMap<DateTime, Supplier<EppResource>> resourceAtTimes =
ImmutableMap.copyOf(
Maps.asMap(dates, input -> loadAtPointInTimeAsync(resource, input)));
// Convert resource to an XML fragment for each watermark/mode pair lazily and cache
// the result.
RdeFragmenter fragmenter = new RdeFragmenter(resourceAtTimes, marshaller);
List<KV<PendingDeposit, DepositFragment>> results = new ArrayList<>();
for (String tld : tlds) {
for (PendingDeposit pending : pendings.get(tld)) {
// Hosts and contacts don't get included in BRDA deposits.
if (pending.mode() == RdeMode.THIN && !clazz.equals(DomainBase.class)) {
continue;
}
Optional<DepositFragment> fragment =
fragmenter.marshal(pending.watermark(), pending.mode());
fragment.ifPresent(
depositFragment -> results.add(KV.of(pending, depositFragment)));
}
}
return results;
});
}
/**
* Decodes the pipeline option extracted from the URL parameter sent by the pipeline launcher to
* the original TLD to pending deposit map.
*/
@SuppressWarnings("unchecked")
static ImmutableSetMultimap<String, PendingDeposit> decodePendings(String encodedPending)
throws IOException, ClassNotFoundException {
try (ObjectInputStream ois =
new ObjectInputStream(
new ByteArrayInputStream(
BaseEncoding.base64Url().omitPadding().decode(encodedPending)))) {
return (ImmutableSetMultimap<String, PendingDeposit>) ois.readObject();
}
}
/**
* Encodes the TLD to pending deposit map in an URL safe string that is sent to the pipeline
* worker by the pipeline launcher as a pipeline option.
*/
public static String encodePendings(ImmutableSetMultimap<String, PendingDeposit> pendings)
throws IOException {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(pendings);
oos.flush();
return BaseEncoding.base64Url().omitPadding().encode(baos.toByteArray());
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
PipelineOptionsFactory.register(RdePipelineOptions.class);
RdePipelineOptions options = PipelineOptionsFactory.fromArgs(args).as(RdePipelineOptions.class);
new RdePipeline(options).run();
}
}

View File

@@ -12,12 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.tools.params;
package google.registry.beam.rde;
import google.registry.model.common.DatabaseTransitionSchedule.TransitionId;
import google.registry.beam.common.RegistryPipelineOptions;
import org.apache.beam.sdk.options.Description;
/**
* {@link TransitionId} CLI parameter converter/validator. Required to support multi-value
* TransitionId parameters.
*/
public final class TransitionIdParameter extends EnumParameter<TransitionId> {}
/** Custom options for running the spec11 pipeline. */
public interface RdePipelineOptions extends RegistryPipelineOptions {
@Description("The Base64-encoded serialized map of TLDs to PendingDeposit.")
String getPendings();
void setPendings(String value);
@Description("The validation mode (LENIENT|STRICT) that the RDE marshaller uses.")
String getValidationMode();
void setValidationMode(String value);
}

View File

@@ -23,10 +23,13 @@ import dagger.Component;
import dagger.Module;
import dagger.Provides;
import google.registry.beam.common.RegistryJpaIO;
import google.registry.beam.common.RegistryJpaIO.Read;
import google.registry.beam.spec11.SafeBrowsingTransforms.EvaluateSafeBrowsingFn;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.model.domain.DomainBase;
import google.registry.model.reporting.Spec11ThreatMatch;
import google.registry.model.reporting.Spec11ThreatMatch.ThreatType;
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
import google.registry.util.Retrier;
import google.registry.util.SqlTemplate;
import google.registry.util.UtilsModule;
@@ -96,21 +99,11 @@ public class Spec11Pipeline implements Serializable {
}
void setupPipeline(Pipeline pipeline) {
options.setIsolationOverride(TransactionIsolationLevel.TRANSACTION_READ_COMMITTED);
PCollection<Subdomain> domains =
pipeline.apply(
"Read active domains from BigQuery",
BigQueryIO.read(Subdomain::parseFromRecord)
.fromQuery(
SqlTemplate.create(getQueryFromFile(Spec11Pipeline.class, "subdomains.sql"))
.put("PROJECT_ID", options.getProject())
.put("DATASTORE_EXPORT_DATASET", "latest_datastore_export")
.put("REGISTRAR_TABLE", "Registrar")
.put("DOMAIN_BASE_TABLE", "DomainBase")
.build())
.withCoder(SerializableCoder.of(Subdomain.class))
.usingStandardSql()
.withoutValidation()
.withTemplateCompatibility());
options.getDatabase().equals("DATASTORE")
? readFromBigQuery(options, pipeline)
: readFromCloudSql(pipeline);
PCollection<KV<Subdomain, ThreatMatch>> threatMatches =
domains.apply("Run through SafeBrowsing API", ParDo.of(safeBrowsingFn));
@@ -119,6 +112,48 @@ public class Spec11Pipeline implements Serializable {
saveToGcs(threatMatches, options);
}
static PCollection<Subdomain> readFromCloudSql(Pipeline pipeline) {
Read<Object[], Subdomain> read =
RegistryJpaIO.read(
"select d, r.emailAddress from Domain d join Registrar r on"
+ " d.currentSponsorClientId = r.clientIdentifier where r.type = 'REAL'"
+ " and d.deletionTime > now()",
false,
Spec11Pipeline::parseRow);
return pipeline.apply("Read active domains from Cloud SQL", read);
}
static PCollection<Subdomain> readFromBigQuery(Spec11PipelineOptions options, Pipeline pipeline) {
return pipeline.apply(
"Read active domains from BigQuery",
BigQueryIO.read(Subdomain::parseFromRecord)
.fromQuery(
SqlTemplate.create(getQueryFromFile(Spec11Pipeline.class, "subdomains.sql"))
.put("PROJECT_ID", options.getProject())
.put("DATASTORE_EXPORT_DATASET", "latest_datastore_export")
.put("REGISTRAR_TABLE", "Registrar")
.put("DOMAIN_BASE_TABLE", "DomainBase")
.build())
.withCoder(SerializableCoder.of(Subdomain.class))
.usingStandardSql()
.withoutValidation()
.withTemplateCompatibility());
}
private static Subdomain parseRow(Object[] row) {
DomainBase domainBase = (DomainBase) row[0];
String emailAddress = (String) row[1];
if (emailAddress == null) {
emailAddress = "";
}
return Subdomain.create(
domainBase.getDomainName(),
domainBase.getRepoId(),
domainBase.getCurrentSponsorClientId(),
emailAddress);
}
static void saveToSql(
PCollection<KV<Subdomain, ThreatMatch>> threatMatches, Spec11PipelineOptions options) {
String transformId = "Spec11 Threat Matches";

View File

@@ -34,4 +34,9 @@ public interface Spec11PipelineOptions extends RegistryPipelineOptions {
String getReportingBucketUrl();
void setReportingBucketUrl(String value);
@Description("The database to read data from.")
String getDatabase();
void setDatabase(String value);
}

View File

@@ -416,17 +416,6 @@ public final class RegistryConfig {
return Optional.ofNullable(config.cloudDns.servicePath);
}
/**
* Returns size of Google Cloud Storage client connection buffer in bytes.
*
* @see google.registry.gcs.GcsUtils
*/
@Provides
@Config("gcsBufferSize")
public static int provideGcsBufferSize() {
return 1024 * 1024;
}
/**
* Returns the email address of the admin account on the G Suite app used to perform
* administrative actions.
@@ -1288,6 +1277,18 @@ public final class RegistryConfig {
return config.sslCertificateValidation.minimumRsaKeyLength;
}
@Provides
@Config("expirationWarningEmailBodyText")
public static String provideExpirationWarningEmailBodyText(RegistryConfigSettings config) {
return config.sslCertificateValidation.expirationWarningEmailBodyText;
}
@Provides
@Config("expirationWarningEmailSubjectText")
public static String provideExpirationWarningEmailSubjectText(RegistryConfigSettings config) {
return config.sslCertificateValidation.expirationWarningEmailSubjectText;
}
@Provides
@Config("allowedEcdsaCurves")
public static ImmutableSet<String> provideAllowedEcdsaCurves(RegistryConfigSettings config) {
@@ -1502,22 +1503,6 @@ public final class RegistryConfig {
CONFIG_SETTINGS.get().cloudSql.replicateTransactions = replicateTransactions;
}
/**
* Returns whether or not to replay commit logs to the SQL database after export to GCS.
*
* <p>If true, we will trigger the {@link google.registry.backup.ReplayCommitLogsToSqlAction}
* after the {@link google.registry.backup.ExportCommitLogDiffAction} to load the commit logs and
* replay them to SQL.
*/
public static boolean getCloudSqlReplayCommitLogs() {
return CONFIG_SETTINGS.get().cloudSql.replayCommitLogs;
}
@VisibleForTesting
public static void overrideCloudSqlReplayCommitLogs(boolean replayCommitLogs) {
CONFIG_SETTINGS.get().cloudSql.replayCommitLogs = replayCommitLogs;
}
/** Returns the roid suffix to be used for the roids of all contacts and hosts. */
public static String getContactAndHostRoidSuffix() {
return CONFIG_SETTINGS.get().registryPolicy.contactAndHostRoidSuffix;

View File

@@ -127,7 +127,6 @@ public class RegistryConfigSettings {
public String username;
public String instanceConnectionName;
public boolean replicateTransactions;
public boolean replayCommitLogs;
}
/** Configuration for Apache Beam (Cloud Dataflow). */
@@ -231,5 +230,7 @@ public class RegistryConfigSettings {
public int expirationWarningDays;
public int minimumRsaKeyLength;
public Set<String> allowedEcdsaCurves;
public String expirationWarningEmailBodyText;
public String expirationWarningEmailSubjectText;
}
}

View File

@@ -230,8 +230,6 @@ cloudSql:
# Set this to true to replicate cloud SQL transactions to datastore in the
# background.
replicateTransactions: false
# Set this to true to enable replay of commit logs to SQL
replayCommitLogs: false
cloudDns:
# Set both properties to null in Production.
@@ -454,6 +452,13 @@ sslCertificateValidation:
# The number of days before a certificate expires that indicates the
# certificate is nearing expiration and warnings should be sent.
expirationWarningDays: 30
# Text for expiring certificate notification email subject.
expirationWarningEmailSubjectText: Certificate Expring Within 30 Days.
# Text for expiring certificate notification email body that accepts 3 parameters:
# registrar name, certificate type, and expiration date, respectively.
expirationWarningEmailBodyText: |
Hello Registrar %s,
The %s certificate is expiring on %s.
# The minimum number of bits an RSA key must contain.
minimumRsaKeyLength: 2048
# The ECDSA curves that are allowed for public keys.

View File

@@ -284,9 +284,10 @@ public class CloudDnsWriter extends BaseDnsWriter {
.filter(hostName -> hostName.endsWith("." + domainName) && !hostName.equals(domainName));
}
/** Mutate the zone with the provided {@code desiredRecords}. */
/** Mutate the zone with the provided map of hostnames to desired DNS records. */
@VisibleForTesting
void mutateZone(ImmutableMap<String, ImmutableSet<ResourceRecordSet>> desiredRecords) {
logger.atInfo().log("Updating DNS records for hostname(s) %s.", desiredRecords.keySet());
// Fetch all existing records for names that this writer is trying to modify
ImmutableSet.Builder<ResourceRecordSet> flattenedExistingRecords = new ImmutableSet.Builder<>();
@@ -313,7 +314,12 @@ public class CloudDnsWriter extends BaseDnsWriter {
desiredRecords.values().forEach(flattenedDesiredRecords::addAll);
// Delete all existing records and add back the desired records
updateResourceRecords(flattenedDesiredRecords.build(), flattenedExistingRecords.build());
try {
updateResourceRecords(flattenedDesiredRecords.build(), flattenedExistingRecords.build());
} catch (IOException e) {
throw new RuntimeException(
"Error updating DNS records for hostname(s) " + desiredRecords.keySet(), e);
}
}
/**
@@ -363,10 +369,12 @@ public class CloudDnsWriter extends BaseDnsWriter {
*
* @throws ZoneStateException if the operation could not be completely successfully because the
* records to delete do not exist, already exist or have been modified with different
* attributes since being queried.
* attributes since being queried. These errors will be retried.
* @throws IOException on non-retryable API errors, e.g. invalid request.
*/
private void updateResourceRecords(
ImmutableSet<ResourceRecordSet> additions, ImmutableSet<ResourceRecordSet> deletions) {
ImmutableSet<ResourceRecordSet> additions, ImmutableSet<ResourceRecordSet> deletions)
throws IOException {
// Find records that are both in additions and deletions, so we can remove them from both before
// requesting the change. This is mostly for optimization reasons - not doing so doesn't affect
// the result.
@@ -392,17 +400,15 @@ public class CloudDnsWriter extends BaseDnsWriter {
GoogleJsonError err = e.getDetails();
// We did something really wrong here, just give up and re-throw
if (err == null || err.getErrors().size() > 1) {
throw new RuntimeException(e);
throw e;
}
String errorReason = err.getErrors().get(0).getReason();
if (RETRYABLE_EXCEPTION_REASONS.contains(errorReason)) {
throw new ZoneStateException(errorReason);
} else {
throw new RuntimeException(e);
throw e;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}

View File

@@ -199,6 +199,15 @@
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=replay-commit-logs-to-sql&endpoint=/_dr/task/replayCommitLogsToSql&runInEmpty]]></url>
<description>
Replays recent commit logs from Datastore to the SQL secondary backend.
</description>
<schedule>every 3 minutes</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<description>

View File

@@ -237,6 +237,12 @@
<url-pattern>/_dr/task/killCommitLogs</url-pattern>
</servlet-mapping>
<!-- Replays Datastore commit logs to SQL. -->
<servlet-mapping>
<servlet-name>backend-servlet</servlet-name>
<url-pattern>/_dr/task/replayCommitLogsToSql</url-pattern>
</servlet-mapping>
<!-- MapReduce servlet. -->
<servlet>
<servlet-name>mapreduce</servlet-name>

View File

@@ -41,6 +41,11 @@
<property name="nsHosts" direction="asc"/>
<property name="deletionTime" direction="asc"/>
</datastore-index>
<!-- For deleting expired not-previously-deleted domains. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<property name="deletionTime" direction="asc"/>
<property name="autorenewEndTime" direction="asc"/>
</datastore-index>
<!-- For RDAP searches by linked nameserver. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<property name="nsHosts" direction="asc"/>

View File

@@ -200,4 +200,12 @@
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=replay-commit-logs-to-sql&endpoint=/_dr/task/replayCommitLogsToSql&runInEmpty]]></url>
<description>
Replays recent commit logs from Datastore to the SQL secondary backend.
</description>
<schedule>every 3 minutes</schedule>
<target>backend</target>
</cron>
</cronentries>

View File

@@ -1,6 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
@@ -100,4 +111,21 @@
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=replay-commit-logs-to-sql&endpoint=/_dr/task/replayCommitLogsToSql&runInEmpty]]></url>
<description>
Replays recent commit logs from Datastore to the SQL secondary backend.
</description>
<schedule>every 3 minutes</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/commitLogCheckpoint]]></url>
<description>
This job checkpoints the commit log buckets and exports the diff since last checkpoint to GCS.
</description>
<schedule>every 3 minutes synchronized</schedule>
<target>backend</target>
</cron>
</cronentries>

View File

@@ -229,4 +229,12 @@
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=replay-commit-logs-to-sql&endpoint=/_dr/task/replayCommitLogsToSql&runInEmpty&dryRun=true]]></url>
<description>
Replays recent commit logs from Datastore to the SQL secondary backend.
</description>
<schedule>every 3 minutes</schedule>
<target>backend</target>
</cron>
</cronentries>

View File

@@ -14,20 +14,19 @@
package google.registry.export;
import static com.google.appengine.tools.cloudstorage.GcsServiceFactory.createGcsService;
import static com.google.common.base.Verify.verifyNotNull;
import static google.registry.mapreduce.inputs.EppResourceInputs.createEntityInput;
import static google.registry.model.EppResourceUtils.isActive;
import static google.registry.model.registry.Registries.getTldsOfType;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.joda.time.DateTimeZone.UTC;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.RetryParams;
import com.google.appengine.tools.mapreduce.Mapper;
import com.google.appengine.tools.mapreduce.Reducer;
import com.google.appengine.tools.mapreduce.ReducerInput;
import com.google.cloud.storage.BlobId;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Suppliers;
@@ -45,12 +44,14 @@ import google.registry.request.Action;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.storage.drive.DriveConnection;
import google.registry.util.Clock;
import google.registry.util.NonFinalForTesting;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;
import java.util.function.Supplier;
import javax.inject.Inject;
import org.joda.time.DateTime;
@@ -70,26 +71,112 @@ public class ExportDomainListsAction implements Runnable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final int MAX_NUM_REDUCE_SHARDS = 100;
public static final String REGISTERED_DOMAINS_FILENAME = "registered_domains.txt";
@Inject MapreduceRunner mrRunner;
@Inject Response response;
@Inject Clock clock;
@Inject DriveConnection driveConnection;
@Inject GcsUtils gcsUtils;
@Inject @Config("domainListsGcsBucket") String gcsBucket;
@Inject @Config("gcsBufferSize") int gcsBufferSize;
@Inject ExportDomainListsAction() {}
@Override
public void run() {
ImmutableSet<String> realTlds = getTldsOfType(TldType.REAL);
logger.atInfo().log("Exporting domain lists for tlds %s", realTlds);
mrRunner
.setJobName("Export domain lists")
.setModuleName("backend")
.setDefaultReduceShards(Math.min(realTlds.size(), MAX_NUM_REDUCE_SHARDS))
.runMapreduce(
new ExportDomainListsMapper(DateTime.now(UTC), realTlds),
new ExportDomainListsReducer(gcsBucket, gcsBufferSize),
ImmutableList.of(createEntityInput(DomainBase.class)))
.sendLinkToMapreduceConsole(response);
if (tm().isOfy()) {
mrRunner
.setJobName("Export domain lists")
.setModuleName("backend")
.setDefaultReduceShards(Math.min(realTlds.size(), MAX_NUM_REDUCE_SHARDS))
.runMapreduce(
new ExportDomainListsMapper(clock.nowUtc(), realTlds),
new ExportDomainListsReducer(gcsBucket, gcsUtils),
ImmutableList.of(createEntityInput(DomainBase.class)))
.sendLinkToMapreduceConsole(response);
} else {
realTlds.forEach(
tld -> {
List<String> domains =
tm().transact(
() ->
// Note that if we had "creationTime <= :now" in the condition (not
// necessary as there is no pending creation, the order of deletionTime
// and creationTime in the query would have been significant and it
// should come after deletionTime. When Hibernate substitutes "now" it
// will first validate that the **first** field that is to be compared
// with it (deletionTime) is assignable from the substituted Java object
// (click.nowUtc()). Since creationTime is a CreateAutoTimestamp, if it
// comes first, we will need to substitute "now" with
// CreateAutoTimestamp.create(clock.nowUtc()). This might look a bit
// strange as the Java object type is clearly incompatible between the
// two fields deletionTime (DateTime) and creationTime, yet they are
// compared with the same "now". It is actually OK because in the end
// Hibernate converts everything to SQL types (and Java field names to
// SQL column names) to run the query. Both CreateAutoTimestamp and
// DateTime are persisted as timestamp_z in SQL. It is only the
// validation that compares the Java types, and only with the first
// field that compares with the substituted value.
jpaTm()
.query(
"SELECT fullyQualifiedDomainName FROM Domain "
+ "WHERE tld = :tld "
+ "AND deletionTime > :now "
+ "ORDER by fullyQualifiedDomainName ASC",
String.class)
.setParameter("tld", tld)
.setParameter("now", clock.nowUtc())
.getResultList());
String domainsList = Joiner.on("\n").join(domains);
logger.atInfo().log(
"Exporting %d domains for TLD %s to GCS and Drive.", domains.size(), tld);
exportToGcs(tld, domainsList, gcsBucket, gcsUtils);
exportToDrive(tld, domainsList, driveConnection);
});
}
}
protected static boolean exportToDrive(
String tld, String domains, DriveConnection driveConnection) {
verifyNotNull(driveConnection, "Expecting non-null driveConnection");
try {
Registry registry = Registry.get(tld);
if (registry.getDriveFolderId() == null) {
logger.atInfo().log(
"Skipping registered domains export for TLD %s because Drive folder isn't specified",
tld);
} else {
String resultMsg =
driveConnection.createOrUpdateFile(
REGISTERED_DOMAINS_FILENAME,
MediaType.PLAIN_TEXT_UTF_8,
registry.getDriveFolderId(),
domains.getBytes(UTF_8));
logger.atInfo().log(
"Exporting registered domains succeeded for TLD %s, response was: %s", tld, resultMsg);
}
} catch (Throwable e) {
logger.atSevere().withCause(e).log(
"Error exporting registered domains for TLD %s to Drive, skipping...", tld);
return false;
}
return true;
}
protected static boolean exportToGcs(
String tld, String domains, String gcsBucket, GcsUtils gcsUtils) {
BlobId blobId = BlobId.of(gcsBucket, tld + ".txt");
try (OutputStream gcsOutput = gcsUtils.openOutputStream(blobId);
Writer osWriter = new OutputStreamWriter(gcsOutput, UTF_8)) {
osWriter.write(domains);
} catch (Throwable e) {
logger.atSevere().withCause(e).log(
"Error exporting registered domains for TLD %s to GCS, skipping...", tld);
return false;
}
return true;
}
static class ExportDomainListsMapper extends Mapper<DomainBase, String, String> {
@@ -122,11 +209,8 @@ public class ExportDomainListsAction implements Runnable {
private static Supplier<DriveConnection> driveConnectionSupplier =
Suppliers.memoize(() -> DaggerDriveModule_DriveComponent.create().driveConnection());
static final String REGISTERED_DOMAINS_FILENAME = "registered_domains.txt";
static final MediaType EXPORT_MIME_TYPE = MediaType.PLAIN_TEXT_UTF_8;
private final String gcsBucket;
private final int gcsBufferSize;
private final GcsUtils gcsUtils;
/**
* Non-serializable {@link DriveConnection} that will be created when an instance of {@link
@@ -136,9 +220,9 @@ public class ExportDomainListsAction implements Runnable {
*/
private transient DriveConnection driveConnection;
public ExportDomainListsReducer(String gcsBucket, int gcsBufferSize) {
public ExportDomainListsReducer(String gcsBucket, GcsUtils gcsUtils) {
this.gcsBucket = gcsBucket;
this.gcsBufferSize = gcsBufferSize;
this.gcsUtils = gcsUtils;
}
@SuppressWarnings("unused")
@@ -147,53 +231,21 @@ public class ExportDomainListsAction implements Runnable {
driveConnection = driveConnectionSupplier.get();
}
private void exportToDrive(String tld, String domains) {
verifyNotNull(driveConnection, "expecting non-null driveConnection");
try {
Registry registry = Registry.get(tld);
if (registry.getDriveFolderId() == null) {
logger.atInfo().log(
"Skipping registered domains export for TLD %s because Drive folder isn't specified",
tld);
} else {
String resultMsg =
driveConnection.createOrUpdateFile(
REGISTERED_DOMAINS_FILENAME,
EXPORT_MIME_TYPE,
registry.getDriveFolderId(),
domains.getBytes(UTF_8));
logger.atInfo().log(
"Exporting registered domains succeeded for TLD %s, response was: %s",
tld, resultMsg);
}
} catch (Throwable e) {
logger.atSevere().withCause(e).log(
"Error exporting registered domains for TLD %s to Drive", tld);
}
getContext().incrementCounter("domain lists written out to Drive");
}
private void exportToGcs(String tld, String domains) {
GcsFilename filename = new GcsFilename(gcsBucket, tld + ".txt");
GcsUtils cloudStorage =
new GcsUtils(createGcsService(RetryParams.getDefaultInstance()), gcsBufferSize);
try (OutputStream gcsOutput = cloudStorage.openOutputStream(filename);
Writer osWriter = new OutputStreamWriter(gcsOutput, UTF_8)) {
osWriter.write(domains);
} catch (IOException e) {
logger.atSevere().withCause(e).log(
"Error exporting registered domains for TLD %s to GCS.", tld);
}
getContext().incrementCounter("domain lists written out to GCS");
}
@Override
public void reduce(String tld, ReducerInput<String> fqdns) {
ImmutableList<String> domains = ImmutableList.sortedCopyOf(() -> fqdns);
String domainsList = Joiner.on('\n').join(domains);
logger.atInfo().log("Exporting %d domains for TLD %s to GCS and Drive.", domains.size(), tld);
exportToGcs(tld, domainsList);
exportToDrive(tld, domainsList);
if (exportToGcs(tld, domainsList, gcsBucket, gcsUtils)) {
getContext().incrementCounter("domain lists successful written out to GCS");
} else {
getContext().incrementCounter("domain lists failed to write out to GCS");
}
if (exportToDrive(tld, domainsList, driveConnection)) {
getContext().incrementCounter("domain lists successfully written out to Drive");
} else {
getContext().incrementCounter("domain lists failed to write out to Drive");
}
}
@VisibleForTesting

View File

@@ -113,7 +113,7 @@ public class ExportPremiumTermsAction implements Runnable {
"Skipping premium terms export for TLD %s because Drive folder isn't specified", tld);
return Optional.of("Skipping export because no Drive folder is associated with this TLD");
}
if (!registry.getPremiumList().isPresent()) {
if (!registry.getPremiumListName().isPresent()) {
logger.atInfo().log("No premium terms to export for TLD %s", tld);
return Optional.of("No premium lists configured");
}
@@ -137,8 +137,8 @@ public class ExportPremiumTermsAction implements Runnable {
}
private String getFormattedPremiumTerms(Registry registry) {
checkState(registry.getPremiumList().isPresent(), "%s does not have a premium list", tld);
String premiumListName = registry.getPremiumList().get().getName();
checkState(registry.getPremiumListName().isPresent(), "%s does not have a premium list", tld);
String premiumListName = registry.getPremiumListName().get();
checkState(
PremiumListDao.getLatestRevision(premiumListName).isPresent(),
"Could not load premium list for " + tld);

View File

@@ -63,7 +63,7 @@ public class ExportReservedTermsAction implements Runnable {
try {
Registry registry = Registry.get(tld);
String resultMsg;
if (registry.getReservedLists().isEmpty() && isNullOrEmpty(registry.getDriveFolderId())) {
if (registry.getReservedListNames().isEmpty() && isNullOrEmpty(registry.getDriveFolderId())) {
resultMsg = "No reserved lists configured";
logger.atInfo().log("No reserved terms to export for TLD %s", tld);
} else if (registry.getDriveFolderId() == null) {

View File

@@ -15,11 +15,11 @@
package google.registry.export;
import com.google.common.base.Joiner;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.registry.Registry;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import google.registry.model.registry.label.ReservedListDao;
import java.util.Set;
import java.util.TreeSet;
import javax.inject.Inject;
@@ -39,8 +39,13 @@ public final class ExportUtils {
public String exportReservedTerms(Registry registry) {
StringBuilder termsBuilder = new StringBuilder(reservedTermsExportDisclaimer).append("\n");
Set<String> reservedTerms = new TreeSet<>();
for (Key<ReservedList> key : registry.getReservedLists()) {
ReservedList reservedList = ReservedList.load(key).get();
for (String reservedListName : registry.getReservedListNames()) {
ReservedList reservedList =
ReservedListDao.getLatestRevision(reservedListName)
.orElseThrow(
() ->
new IllegalStateException(
String.format("Reserved list %s does not exist", reservedListName)));
if (reservedList.getShouldPublish()) {
for (ReservedListEntry entry : reservedList.getReservedListEntries().values()) {
reservedTerms.add(entry.getLabel());

View File

@@ -15,6 +15,7 @@
package google.registry.flows;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.base.Strings;
import dagger.Module;
@@ -222,6 +223,7 @@ public class FlowModule {
String clientId,
EppInput eppInput) {
builder
.setModificationTime(tm().getTransactionTime())
.setTrid(trid)
.setXmlBytes(inputXmlBytes)
.setBySuperuser(isSuperuser)

View File

@@ -15,6 +15,7 @@
package google.registry.flows;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.model.IdService.allocateId;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.xml.ValidationMode.LENIENT;
import static google.registry.xml.ValidationMode.STRICT;
@@ -33,7 +34,6 @@ import google.registry.model.eppcommon.EppXmlTransformer;
import google.registry.model.eppinput.EppInput.WrongProtocolVersionException;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.host.InetAddressAdapter.IpVersionMismatchException;
import google.registry.model.ofy.ObjectifyService;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.translators.CurrencyUnitAdapter.UnknownCurrencyException;
import google.registry.xml.XmlException;
@@ -105,7 +105,7 @@ public final class FlowUtils {
public static <H extends HistoryEntry> Key<H> createHistoryKey(
EppResource parent, Class<H> clazz) {
return Key.create(Key.create(parent), clazz, ObjectifyService.allocateId());
return Key.create(Key.create(parent), clazz, allocateId());
}
/** Registrar is not logged in. */

View File

@@ -19,6 +19,7 @@ import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist
import static google.registry.flows.contact.ContactFlowUtils.validateAsciiPostalInfo;
import static google.registry.flows.contact.ContactFlowUtils.validateContactAgainstPolicy;
import static google.registry.model.EppResourceUtils.createRepoId;
import static google.registry.model.IdService.allocateId;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableSet;
@@ -41,7 +42,6 @@ import google.registry.model.eppoutput.CreateData.ContactCreateData;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.ObjectifyService;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import javax.inject.Inject;
@@ -81,7 +81,7 @@ public final class ContactCreateFlow implements TransactionalFlow {
.setAuthInfo(command.getAuthInfo())
.setCreationClientId(clientId)
.setPersistedCurrentSponsorClientId(clientId)
.setRepoId(createRepoId(ObjectifyService.allocateId(), roidSuffix))
.setRepoId(createRepoId(allocateId(), roidSuffix))
.setFaxNumber(command.getFax())
.setVoiceNumber(command.getVoice())
.setDisclose(command.getDisclose())
@@ -93,7 +93,6 @@ public final class ContactCreateFlow implements TransactionalFlow {
validateContactAgainstPolicy(newContact);
historyBuilder
.setType(HistoryEntry.Type.CONTACT_CREATE)
.setModificationTime(now)
.setXmlBytes(null) // We don't want to store contact details in the history entry.
.setContact(newContact);
tm().insertAll(

View File

@@ -122,11 +122,7 @@ public final class ContactDeleteFlow implements TransactionalFlow {
resultCode = SUCCESS;
}
ContactHistory contactHistory =
historyBuilder
.setType(historyEntryType)
.setModificationTime(now)
.setContact(newContact)
.build();
historyBuilder.setType(historyEntryType).setContact(newContact).build();
if (!tm().isOfy()) {
handlePendingTransferOnDelete(existingContact, newContact, now, contactHistory);
}

View File

@@ -22,6 +22,7 @@ import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.contact.ContactFlowUtils.createGainingTransferPollMessage;
import static google.registry.flows.contact.ContactFlowUtils.createTransferResponse;
import static google.registry.model.ResourceTransferUtils.approvePendingTransfer;
import static google.registry.model.reporting.HistoryEntry.Type.CONTACT_TRANSFER_APPROVE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableSet;
@@ -39,7 +40,6 @@ import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferStatus;
import java.util.Optional;
@@ -88,11 +88,7 @@ public final class ContactTransferApproveFlow implements TransactionalFlow {
ContactResource newContact =
approvePendingTransfer(existingContact, TransferStatus.CLIENT_APPROVED, now);
ContactHistory contactHistory =
historyBuilder
.setType(HistoryEntry.Type.CONTACT_TRANSFER_APPROVE)
.setModificationTime(now)
.setContact(newContact)
.build();
historyBuilder.setType(CONTACT_TRANSFER_APPROVE).setContact(newContact).build();
// Create a poll message for the gaining client.
PollMessage gainingPollMessage =
createGainingTransferPollMessage(

View File

@@ -22,6 +22,7 @@ import static google.registry.flows.ResourceFlowUtils.verifyTransferInitiator;
import static google.registry.flows.contact.ContactFlowUtils.createLosingTransferPollMessage;
import static google.registry.flows.contact.ContactFlowUtils.createTransferResponse;
import static google.registry.model.ResourceTransferUtils.denyPendingTransfer;
import static google.registry.model.reporting.HistoryEntry.Type.CONTACT_TRANSFER_CANCEL;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableSet;
@@ -39,7 +40,6 @@ import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferStatus;
import java.util.Optional;
@@ -84,11 +84,7 @@ public final class ContactTransferCancelFlow implements TransactionalFlow {
ContactResource newContact =
denyPendingTransfer(existingContact, TransferStatus.CLIENT_CANCELLED, now, clientId);
ContactHistory contactHistory =
historyBuilder
.setType(HistoryEntry.Type.CONTACT_TRANSFER_CANCEL)
.setModificationTime(now)
.setContact(newContact)
.build();
historyBuilder.setType(CONTACT_TRANSFER_CANCEL).setContact(newContact).build();
// Create a poll message for the losing client.
PollMessage losingPollMessage =
createLosingTransferPollMessage(

View File

@@ -22,6 +22,7 @@ import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.contact.ContactFlowUtils.createGainingTransferPollMessage;
import static google.registry.flows.contact.ContactFlowUtils.createTransferResponse;
import static google.registry.model.ResourceTransferUtils.denyPendingTransfer;
import static google.registry.model.reporting.HistoryEntry.Type.CONTACT_TRANSFER_REJECT;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableSet;
@@ -38,7 +39,6 @@ import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferStatus;
import java.util.Optional;
@@ -82,11 +82,7 @@ public final class ContactTransferRejectFlow implements TransactionalFlow {
ContactResource newContact =
denyPendingTransfer(existingContact, TransferStatus.CLIENT_REJECTED, now, clientId);
ContactHistory contactHistory =
historyBuilder
.setType(HistoryEntry.Type.CONTACT_TRANSFER_REJECT)
.setModificationTime(now)
.setContact(newContact)
.build();
historyBuilder.setType(CONTACT_TRANSFER_REJECT).setContact(newContact).build();
PollMessage gainingPollMessage =
createGainingTransferPollMessage(
targetId, newContact.getTransferData(), now, Key.create(contactHistory));

View File

@@ -24,6 +24,7 @@ import static google.registry.flows.contact.ContactFlowUtils.createGainingTransf
import static google.registry.flows.contact.ContactFlowUtils.createLosingTransferPollMessage;
import static google.registry.flows.contact.ContactFlowUtils.createTransferResponse;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
import static google.registry.model.reporting.HistoryEntry.Type.CONTACT_TRANSFER_REQUEST;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableSet;
@@ -45,7 +46,6 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.ContactTransferData;
import google.registry.model.transfer.TransferStatus;
@@ -120,10 +120,7 @@ public final class ContactTransferRequestFlow implements TransactionalFlow {
.setTransferStatus(TransferStatus.SERVER_APPROVED)
.build();
Key<ContactHistory> contactHistoryKey = createHistoryKey(existingContact, ContactHistory.class);
historyBuilder
.setId(contactHistoryKey.getId())
.setType(HistoryEntry.Type.CONTACT_TRANSFER_REQUEST)
.setModificationTime(now);
historyBuilder.setId(contactHistoryKey.getId()).setType(CONTACT_TRANSFER_REQUEST);
// If the transfer is server approved, this message will be sent to the losing registrar. */
PollMessage serverApproveLosingPollMessage =
createLosingTransferPollMessage(targetId, serverApproveTransferData, contactHistoryKey);

View File

@@ -24,6 +24,7 @@ import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.contact.ContactFlowUtils.validateAsciiPostalInfo;
import static google.registry.flows.contact.ContactFlowUtils.validateContactAgainstPolicy;
import static google.registry.model.reporting.HistoryEntry.Type.CONTACT_UPDATE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableSet;
@@ -45,7 +46,6 @@ import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import java.util.Optional;
import javax.annotation.Nullable;
@@ -146,8 +146,7 @@ public final class ContactUpdateFlow implements TransactionalFlow {
validateAsciiPostalInfo(newContact.getInternationalizedPostalInfo());
validateContactAgainstPolicy(newContact);
historyBuilder
.setType(HistoryEntry.Type.CONTACT_UPDATE)
.setModificationTime(now)
.setType(CONTACT_UPDATE)
.setXmlBytes(null) // We don't want to store contact details in the history entry.
.setContact(newContact);
tm().insert(historyBuilder.build());

View File

@@ -42,11 +42,13 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNo
import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActive;
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
import static google.registry.model.EppResourceUtils.createDomainRepoId;
import static google.registry.model.IdService.allocateId;
import static google.registry.model.eppcommon.StatusValue.SERVER_HOLD;
import static google.registry.model.registry.Registry.TldState.GENERAL_AVAILABILITY;
import static google.registry.model.registry.Registry.TldState.QUIET_PERIOD;
import static google.registry.model.registry.Registry.TldState.START_DATE_SUNRISE;
import static google.registry.model.registry.label.ReservationType.NAME_COLLISION;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
@@ -99,7 +101,6 @@ import google.registry.model.eppoutput.CreateData.DomainCreateData;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.ObjectifyService;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.poll.PollMessage.Autorenew;
@@ -302,12 +303,9 @@ public class DomainCreateFlow implements TransactionalFlow {
Optional<SecDnsCreateExtension> secDnsCreate =
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
String repoId = createDomainRepoId(ObjectifyService.allocateId(), registry.getTldStr());
String repoId = createDomainRepoId(allocateId(), registry.getTldStr());
Key<DomainHistory> domainHistoryKey =
Key.create(
Key.create(DomainBase.class, repoId),
DomainHistory.class,
ObjectifyService.allocateId());
Key.create(Key.create(DomainBase.class, repoId), DomainHistory.class, allocateId());
historyBuilder.setId(domainHistoryKey.getId());
// Bill for the create.
BillingEvent.OneTime createBillingEvent =
@@ -498,12 +496,7 @@ public class DomainCreateFlow implements TransactionalFlow {
TransactionReportField.netAddsFieldFromYears(period.getValue()),
1)));
}
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setPeriod(period)
.setModificationTime(now)
.setDomain(domain)
.build();
return historyBuilder.setType(DOMAIN_CREATE).setPeriod(period).setDomain(domain).build();
}
private BillingEvent.OneTime createOneTimeBillingEvent(

View File

@@ -34,6 +34,7 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.ADD_FIELDS;
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.RENEW_FIELDS;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_DELETE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
import static google.registry.util.CollectionUtils.nullToEmpty;
@@ -88,7 +89,6 @@ import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldType;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferStatus;
import java.util.Collections;
@@ -331,11 +331,7 @@ public final class DomainDeleteFlow implements TransactionalFlow {
: TransactionReportField.DELETED_DOMAINS_NOGRACE,
1)));
}
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_DELETE)
.setModificationTime(now)
.setDomain(domain)
.build();
return historyBuilder.setType(DOMAIN_DELETE).setDomain(domain).build();
}
private PollMessage.OneTime createDeletePollMessage(

View File

@@ -29,6 +29,7 @@ import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
import static google.registry.flows.domain.DomainFlowUtils.validateRegistrationPeriod;
import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActive;
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_RENEW;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
@@ -73,7 +74,6 @@ import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import java.util.Optional;
import javax.inject.Inject;
@@ -230,9 +230,8 @@ public final class DomainRenewFlow implements TransactionalFlow {
private DomainHistory buildDomainHistory(
DomainBase newDomain, DateTime now, Period period, Duration renewGracePeriod) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_RENEW)
.setType(DOMAIN_RENEW)
.setPeriod(period)
.setModificationTime(now)
.setDomain(newDomain)
.setDomainTransactionRecords(
ImmutableSet.of(

View File

@@ -27,6 +27,7 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyNotReserved;
import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNotBlocked;
import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActive;
import static google.registry.model.ResourceTransferUtils.updateForeignKeyIndexDeletionTime;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_RESTORE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@@ -66,7 +67,6 @@ import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import java.util.Optional;
import javax.inject.Inject;
@@ -188,8 +188,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
private DomainHistory buildDomainHistory(DomainBase newDomain, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_RESTORE)
.setModificationTime(now)
.setType(DOMAIN_RESTORE)
.setDomain(newDomain)
.setDomainTransactionRecords(
ImmutableSet.of(

View File

@@ -29,6 +29,7 @@ import static google.registry.flows.domain.DomainTransferUtils.createGainingTran
import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse;
import static google.registry.model.ResourceTransferUtils.approvePendingTransfer;
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_APPROVE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
import static google.registry.util.CollectionUtils.union;
@@ -58,7 +59,6 @@ import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
@@ -240,8 +240,7 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
registry.getAutomaticTransferLength().plus(registry.getTransferGracePeriodLength()),
ImmutableSet.of(TRANSFER_SUCCESSFUL));
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_APPROVE)
.setModificationTime(now)
.setType(DOMAIN_TRANSFER_APPROVE)
.setOtherClientId(gainingClientId)
.setDomain(newDomain)
.setDomainTransactionRecords(

View File

@@ -27,6 +27,7 @@ import static google.registry.flows.domain.DomainTransferUtils.createLosingTrans
import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse;
import static google.registry.model.ResourceTransferUtils.denyPendingTransfer;
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@@ -46,7 +47,6 @@ import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferStatus;
import java.util.Optional;
@@ -130,8 +130,7 @@ public final class DomainTransferCancelFlow implements TransactionalFlow {
registry.getAutomaticTransferLength().plus(registry.getTransferGracePeriodLength()),
ImmutableSet.of(TRANSFER_SUCCESSFUL));
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL)
.setModificationTime(now)
.setType(DOMAIN_TRANSFER_CANCEL)
.setDomain(newDomain)
.setDomainTransactionRecords(cancelingRecords)
.build();

View File

@@ -28,6 +28,7 @@ import static google.registry.flows.domain.DomainTransferUtils.createTransferRes
import static google.registry.model.ResourceTransferUtils.denyPendingTransfer;
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_NACKED;
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REJECT;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.union;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@@ -48,7 +49,6 @@ import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferStatus;
import java.util.Optional;
@@ -131,8 +131,7 @@ public final class DomainTransferRejectFlow implements TransactionalFlow {
registry.getAutomaticTransferLength().plus(registry.getTransferGracePeriodLength()),
ImmutableSet.of(TRANSFER_SUCCESSFUL));
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_REJECT)
.setModificationTime(now)
.setType(DOMAIN_TRANSFER_REJECT)
.setDomainTransactionRecords(
union(
cancelingRecords,

View File

@@ -32,6 +32,7 @@ import static google.registry.flows.domain.DomainTransferUtils.createPendingTran
import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse;
import static google.registry.flows.domain.DomainTransferUtils.createTransferServerApproveEntities;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableList;
@@ -68,7 +69,6 @@ import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferData.TransferServerApproveEntity;
@@ -315,9 +315,8 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
private DomainHistory buildDomainHistory(
DomainBase newDomain, Registry registry, DateTime now, Period period) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST)
.setType(DOMAIN_TRANSFER_REQUEST)
.setPeriod(period)
.setModificationTime(now)
.setDomain(newDomain)
.setDomainTransactionRecords(
ImmutableSet.of(

View File

@@ -39,6 +39,7 @@ import static google.registry.flows.domain.DomainFlowUtils.validateRegistrantAll
import static google.registry.flows.domain.DomainFlowUtils.validateRequiredContactsPresent;
import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNotProhibited;
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_UPDATE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableSet;
@@ -76,7 +77,6 @@ import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import java.util.Optional;
import javax.inject.Inject;
@@ -166,7 +166,8 @@ public final class DomainUpdateFlow implements TransactionalFlow {
flowCustomLogic.afterValidation(
AfterValidationParameters.newBuilder().setExistingDomain(existingDomain).build());
DomainBase newDomain = performUpdate(command, existingDomain, now);
DomainHistory domainHistory = buildDomainHistory(newDomain, now);
DomainHistory domainHistory =
historyBuilder.setType(DOMAIN_UPDATE).setDomain(newDomain).build();
validateNewState(newDomain);
dnsQueue.addDomainRefreshTask(targetId);
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
@@ -217,14 +218,6 @@ public final class DomainUpdateFlow implements TransactionalFlow {
tld, add.getNameserverFullyQualifiedHostNames());
}
private DomainHistory buildDomainHistory(DomainBase newDomain, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_UPDATE)
.setModificationTime(now)
.setDomain(newDomain)
.build();
}
private DomainBase performUpdate(Update command, DomainBase domain, DateTime now)
throws EppException {
AddRemove add = command.getInnerAdd();

View File

@@ -21,6 +21,8 @@ import static google.registry.flows.host.HostFlowUtils.validateHostName;
import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainNotInPendingDelete;
import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainOwnership;
import static google.registry.model.EppResourceUtils.createRepoId;
import static google.registry.model.IdService.allocateId;
import static google.registry.model.reporting.HistoryEntry.Type.HOST_CREATE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
@@ -49,8 +51,6 @@ import google.registry.model.host.HostHistory;
import google.registry.model.host.HostResource;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.ObjectifyService;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import java.util.Optional;
import javax.inject.Inject;
@@ -126,10 +126,10 @@ public final class HostCreateFlow implements TransactionalFlow {
.setPersistedCurrentSponsorClientId(clientId)
.setHostName(targetId)
.setInetAddresses(command.getInetAddresses())
.setRepoId(createRepoId(ObjectifyService.allocateId(), roidSuffix))
.setRepoId(createRepoId(allocateId(), roidSuffix))
.setSuperordinateDomain(superordinateDomain.map(DomainBase::createVKey).orElse(null))
.build();
historyBuilder.setType(HistoryEntry.Type.HOST_CREATE).setModificationTime(now).setHost(newHost);
historyBuilder.setType(HOST_CREATE).setHost(newHost);
ImmutableSet<ImmutableObject> entitiesToSave =
ImmutableSet.of(
newHost,

View File

@@ -130,7 +130,7 @@ public final class HostDeleteFlow implements TransactionalFlow {
historyEntryType = Type.HOST_DELETE;
resultCode = SUCCESS;
}
historyBuilder.setType(historyEntryType).setModificationTime(now).setHost(newHost);
historyBuilder.setType(historyEntryType).setHost(newHost);
tm().insert(historyBuilder.build());
tm().update(newHost);
return responseBuilder.setResultFromCode(resultCode).build();

View File

@@ -27,6 +27,7 @@ import static google.registry.flows.host.HostFlowUtils.validateHostName;
import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainNotInPendingDelete;
import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainOwnership;
import static google.registry.model.index.ForeignKeyIndex.loadAndGetKey;
import static google.registry.model.reporting.HistoryEntry.Type.HOST_UPDATE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
@@ -57,7 +58,6 @@ import google.registry.model.host.HostCommand.Update.Change;
import google.registry.model.host.HostHistory;
import google.registry.model.host.HostResource;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.persistence.VKey;
import java.util.Objects;
@@ -201,12 +201,7 @@ public final class HostUpdateFlow implements TransactionalFlow {
updateSuperordinateDomains(existingHost, newHost);
}
enqueueTasks(existingHost, newHost);
entitiesToInsert.add(
historyBuilder
.setType(HistoryEntry.Type.HOST_UPDATE)
.setModificationTime(now)
.setHost(newHost)
.build());
entitiesToInsert.add(historyBuilder.setType(HOST_UPDATE).setHost(newHost).build());
tm().updateAll(entitiesToUpdate.build());
tm().insertAll(entitiesToInsert.build());
return responseBuilder.build();

View File

@@ -1,34 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.gcs;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
import com.google.appengine.tools.cloudstorage.RetryParams;
import dagger.Module;
import dagger.Provides;
/** Dagger module for {@link GcsService}. */
@Module
public final class GcsServiceModule {
private static final GcsService gcsService =
GcsServiceFactory.createGcsService(RetryParams.getDefaultInstance());
@Provides
static GcsService provideGcsService() {
return gcsService;
}
}

View File

@@ -14,30 +14,39 @@
package google.registry.gcs;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Iterables.getLast;
import com.google.appengine.tools.cloudstorage.GcsFileMetadata;
import com.google.appengine.tools.cloudstorage.GcsFileOptions;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.appengine.tools.cloudstorage.ListOptions;
import com.google.appengine.tools.cloudstorage.ListResult;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.Storage.BlobListOption;
import com.google.cloud.storage.StorageException;
import com.google.cloud.storage.StorageOptions;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.CredentialModule.DefaultCredential;
import google.registry.util.GoogleCredentialsBundle;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.io.Serializable;
import java.nio.channels.Channels;
import javax.annotation.CheckReturnValue;
import javax.inject.Inject;
/** Utilities for working with Google Cloud Storage. */
public class GcsUtils {
/**
* Utilities for working with Google Cloud Storage.
*
* <p>It is {@link Serializable} so that it can be used in MapReduce or Beam.
*/
public class GcsUtils implements Serializable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -48,30 +57,65 @@ public class GcsUtils {
.put("json", MediaType.JSON_UTF_8)
.build();
private final GcsService gcsService;
private final int bufferSize;
private final StorageOptions storageOptions;
@Inject
public GcsUtils(GcsService gcsService, @Config("gcsBufferSize") int bufferSize) {
this.gcsService = gcsService;
this.bufferSize = bufferSize;
private Storage storage() {
return storageOptions.getService();
}
/** Opens a GCS file for reading as an {@link InputStream} with prefetching. */
@Inject
public GcsUtils(@DefaultCredential GoogleCredentialsBundle credentialsBundle) {
this(
StorageOptions.newBuilder()
.setCredentials(credentialsBundle.getGoogleCredentials())
.build());
}
@VisibleForTesting
public GcsUtils(StorageOptions storageOptions) {
this.storageOptions = storageOptions;
}
/** Opens a GCS file for reading as an {@link InputStream}. */
@CheckReturnValue
public InputStream openInputStream(GcsFilename filename) {
return Channels.newInputStream(gcsService.openPrefetchingReadChannel(filename, 0, bufferSize));
public InputStream openInputStream(BlobId blobId) {
return Channels.newInputStream(storage().reader(blobId));
}
/** Opens a GCS file for writing as an {@link OutputStream}, overwriting existing files. */
@CheckReturnValue
public OutputStream openOutputStream(GcsFilename filename) throws IOException {
return Channels.newOutputStream(gcsService.createOrReplace(filename, getOptions(filename)));
public OutputStream openOutputStream(BlobId blobId) {
return Channels.newOutputStream(storage().writer(createBlobInfo(blobId)));
}
/**
* Opens a GCS file for writing as an {@link OutputStream}, overwriting existing files and setting
* the given metadata.
*/
@CheckReturnValue
public OutputStream openOutputStream(BlobId blobId, ImmutableMap<String, String> metadata) {
return Channels.newOutputStream(
storage().writer(BlobInfo.newBuilder(blobId).setMetadata(metadata).build()));
}
/** Creates a GCS file with the given byte contents, overwriting existing files. */
public void createFromBytes(GcsFilename filename, byte[] bytes) throws IOException {
gcsService.createOrReplace(filename, getOptions(filename), ByteBuffer.wrap(bytes));
public void createFromBytes(BlobId blobId, byte[] bytes) throws StorageException {
createFromBytes(createBlobInfo(blobId), bytes);
}
/** Creates a GCS file with the given byte contents and metadata, overwriting existing files. */
public void createFromBytes(BlobInfo blobInfo, byte[] bytes) throws StorageException {
storage().create(blobInfo, bytes);
}
/** Read the content of the given GCS file and return it in a byte array. */
public byte[] readBytesFrom(BlobId blobId) throws StorageException {
return storage().readAllBytes(blobId);
}
/** Delete the given GCS file. */
public void delete(BlobId blobId) throws StorageException {
storage().delete(blobId);
}
/**
@@ -86,37 +130,55 @@ public class GcsUtils {
*/
public ImmutableList<String> listFolderObjects(String bucketName, String prefix)
throws IOException {
ListResult result =
gcsService.list(bucketName, new ListOptions.Builder().setPrefix(prefix).build());
final ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
result.forEachRemaining(
listItem -> {
if (!listItem.isDirectory()) {
builder.add(listItem.getName().replaceFirst(prefix, ""));
}
});
return builder.build();
return Streams.stream(storage().list(bucketName, BlobListOption.prefix(prefix)).iterateAll())
.map(blob -> blob.getName().substring(prefix.length()))
.collect(toImmutableList());
}
/** Returns {@code true} if a file exists and is non-empty on Google Cloud Storage. */
public boolean existsAndNotEmpty(GcsFilename file) {
GcsFileMetadata metadata;
public boolean existsAndNotEmpty(BlobId blobId) {
try {
metadata = gcsService.getMetadata(file);
} catch (IOException e) {
Blob blob = storage().get(blobId);
return blob != null && blob.getSize() > 0;
} catch (StorageException e) {
logger.atWarning().withCause(e).log("Failed to check if GCS file exists");
return false;
}
return metadata != null && metadata.getLength() > 0;
}
/** Determines most appropriate {@link GcsFileOptions} based on filename extension. */
private static GcsFileOptions getOptions(GcsFilename filename) {
GcsFileOptions.Builder builder = new GcsFileOptions.Builder().cacheControl("no-cache");
MediaType mediaType = EXTENSIONS.get(getLast(Splitter.on('.').split(filename.getObjectName())));
/** Returns the user defined metadata of a GCS file if the file exists, or an empty map. */
public ImmutableMap<String, String> getMetadata(BlobId blobId) throws StorageException {
Blob blob = storage().get(blobId);
return blob == null ? ImmutableMap.of() : ImmutableMap.copyOf(blob.getMetadata());
}
/**
* Returns the {@link BlobInfo} of the given GCS file.
*
* <p>Note that a {@link Blob} is returned, but on the {@link BlobInfo} part of it is usable.
*/
public BlobInfo getBlobInfo(BlobId blobId) throws StorageException {
return storage().get(blobId);
}
/** Determines most appropriate {@link BlobInfo} based on filename extension. */
private static BlobInfo createBlobInfo(BlobId blobId) {
BlobInfo.Builder builder = BlobInfo.newBuilder(blobId).setCacheControl("no-cache");
MediaType mediaType = EXTENSIONS.get(getLast(Splitter.on('.').split(blobId.getName())));
if (mediaType != null) {
builder = builder.mimeType(mediaType.type());
builder = builder.setContentType(mediaType.toString());
}
return builder.build();
}
// These two methods are needed to check whether serialization is done correctly in tests.
@Override
public boolean equals(Object obj) {
return obj instanceof GcsUtils && ((GcsUtils) obj).storageOptions.equals(storageOptions);
}
@Override
public int hashCode() {
return storageOptions.hashCode();
}
}

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