mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 16:07:15 +02:00
Isolate customizable code in activity reporting
Modularize the code for DNS count reporting to allow it to be customized for more flexible systems. Tested: Uploaded to alpha with hacks to allow admin initiating and logging from the DnsCountQueryCoordinatorModule, verified that the provider function is invoked and that the action runs successfully. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=225225587
This commit is contained in:
parent
6966151bed
commit
c396957d15
13 changed files with 208 additions and 12 deletions
|
@ -1135,6 +1135,12 @@ public final class RegistryConfig {
|
||||||
return config.registryPolicy.allocationTokenCustomLogicClass;
|
return config.registryPolicy.allocationTokenCustomLogicClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Config("dnsCountQueryCoordinatorClass")
|
||||||
|
public static String dnsCountQueryCoordinatorClass(RegistryConfigSettings config) {
|
||||||
|
return config.registryPolicy.dnsCountQueryCoordinatorClass;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the disclaimer text for the exported premium terms. */
|
/** Returns the disclaimer text for the exported premium terms. */
|
||||||
@Provides
|
@Provides
|
||||||
@Config("premiumTermsExportDisclaimer")
|
@Config("premiumTermsExportDisclaimer")
|
||||||
|
|
|
@ -77,6 +77,7 @@ public class RegistryConfigSettings {
|
||||||
public String customLogicFactoryClass;
|
public String customLogicFactoryClass;
|
||||||
public String whoisCommandFactoryClass;
|
public String whoisCommandFactoryClass;
|
||||||
public String allocationTokenCustomLogicClass;
|
public String allocationTokenCustomLogicClass;
|
||||||
|
public String dnsCountQueryCoordinatorClass;
|
||||||
public int contactAutomaticTransferDays;
|
public int contactAutomaticTransferDays;
|
||||||
public String greetingServerId;
|
public String greetingServerId;
|
||||||
public List<String> registrarChangesNotificationEmailAddresses;
|
public List<String> registrarChangesNotificationEmailAddresses;
|
||||||
|
|
|
@ -55,6 +55,10 @@ registryPolicy:
|
||||||
# See flows/domain/token/AllocationTokenCustomLogic.java
|
# See flows/domain/token/AllocationTokenCustomLogic.java
|
||||||
allocationTokenCustomLogicClass: google.registry.flows.domain.token.AllocationTokenCustomLogic
|
allocationTokenCustomLogicClass: google.registry.flows.domain.token.AllocationTokenCustomLogic
|
||||||
|
|
||||||
|
# Custom logic class for handling DNS query count reporting for ICANN.
|
||||||
|
# See reporting/icann/DnsCountQueryCoordinator.java
|
||||||
|
dnsCountQueryCoordinatorClass: google.registry.reporting.icann.BasicDnsCountQueryCoordinator
|
||||||
|
|
||||||
# Length of time after which contact transfers automatically conclude.
|
# Length of time after which contact transfers automatically conclude.
|
||||||
contactAutomaticTransferDays: 5
|
contactAutomaticTransferDays: 5
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ import google.registry.reporting.billing.BillingModule;
|
||||||
import google.registry.reporting.billing.CopyDetailReportsAction;
|
import google.registry.reporting.billing.CopyDetailReportsAction;
|
||||||
import google.registry.reporting.billing.GenerateInvoicesAction;
|
import google.registry.reporting.billing.GenerateInvoicesAction;
|
||||||
import google.registry.reporting.billing.PublishInvoicesAction;
|
import google.registry.reporting.billing.PublishInvoicesAction;
|
||||||
|
import google.registry.reporting.icann.DnsCountQueryCoordinatorModule;
|
||||||
import google.registry.reporting.icann.IcannReportingModule;
|
import google.registry.reporting.icann.IcannReportingModule;
|
||||||
import google.registry.reporting.icann.IcannReportingStagingAction;
|
import google.registry.reporting.icann.IcannReportingStagingAction;
|
||||||
import google.registry.reporting.icann.IcannReportingUploadAction;
|
import google.registry.reporting.icann.IcannReportingUploadAction;
|
||||||
|
@ -100,6 +101,7 @@ import google.registry.tmch.TmchSmdrlAction;
|
||||||
BillingModule.class,
|
BillingModule.class,
|
||||||
CloudDnsWriterModule.class,
|
CloudDnsWriterModule.class,
|
||||||
CronModule.class,
|
CronModule.class,
|
||||||
|
DnsCountQueryCoordinatorModule.class,
|
||||||
DnsModule.class,
|
DnsModule.class,
|
||||||
DnsUpdateConfigModule.class,
|
DnsUpdateConfigModule.class,
|
||||||
DnsUpdateWriterModule.class,
|
DnsUpdateWriterModule.class,
|
||||||
|
|
|
@ -29,9 +29,7 @@ import org.joda.time.YearMonth;
|
||||||
import org.joda.time.format.DateTimeFormat;
|
import org.joda.time.format.DateTimeFormat;
|
||||||
import org.joda.time.format.DateTimeFormatter;
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
/**
|
/** Utility class that produces SQL queries used to generate activity reports from Bigquery. */
|
||||||
* Utility class that produces SQL queries used to generate activity reports from Bigquery.
|
|
||||||
*/
|
|
||||||
public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
||||||
|
|
||||||
// Names for intermediary tables for overall activity reporting query.
|
// Names for intermediary tables for overall activity reporting query.
|
||||||
|
@ -42,20 +40,23 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
||||||
static final String WHOIS_COUNTS = "whois_counts";
|
static final String WHOIS_COUNTS = "whois_counts";
|
||||||
static final String ACTIVITY_REPORT_AGGREGATION = "activity_report_aggregation";
|
static final String ACTIVITY_REPORT_AGGREGATION = "activity_report_aggregation";
|
||||||
|
|
||||||
@Inject @Config("projectId") String projectId;
|
@Inject
|
||||||
|
@Config("projectId")
|
||||||
|
String projectId;
|
||||||
|
|
||||||
@Inject YearMonth yearMonth;
|
@Inject YearMonth yearMonth;
|
||||||
|
|
||||||
@Inject ActivityReportingQueryBuilder() {}
|
@Inject DnsCountQueryCoordinator dnsCountQueryCoordinator;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ActivityReportingQueryBuilder() {}
|
||||||
|
|
||||||
/** Returns the aggregate query which generates the activity report from the saved view. */
|
/** Returns the aggregate query which generates the activity report from the saved view. */
|
||||||
@Override
|
@Override
|
||||||
public String getReportQuery() {
|
public String getReportQuery() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"#standardSQL\nSELECT * FROM `%s.%s.%s`",
|
"#standardSQL\nSELECT * FROM `%s.%s.%s`",
|
||||||
projectId,
|
projectId, ICANN_REPORTING_DATA_SET, getTableName(ACTIVITY_REPORT_AGGREGATION));
|
||||||
ICANN_REPORTING_DATA_SET,
|
|
||||||
getTableName(ACTIVITY_REPORT_AGGREGATION));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the month we're doing activity reporting for, and returns the view query map. */
|
/** Sets the month we're doing activity reporting for, and returns the view query map. */
|
||||||
|
@ -67,6 +68,10 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
||||||
return createQueryMap(firstDayOfMonth, lastDayOfMonth);
|
return createQueryMap(firstDayOfMonth, lastDayOfMonth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void prepareForQuery() throws Exception {
|
||||||
|
dnsCountQueryCoordinator.prepareForQuery();
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a map from view name to its associated SQL query. */
|
/** Returns a map from view name to its associated SQL query. */
|
||||||
private ImmutableMap<String, String> createQueryMap(
|
private ImmutableMap<String, String> createQueryMap(
|
||||||
LocalDate firstDayOfMonth, LocalDate lastDayOfMonth) {
|
LocalDate firstDayOfMonth, LocalDate lastDayOfMonth) {
|
||||||
|
@ -80,8 +85,7 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
||||||
.build();
|
.build();
|
||||||
queriesBuilder.put(getTableName(REGISTRAR_OPERATING_STATUS), operationalRegistrarsQuery);
|
queriesBuilder.put(getTableName(REGISTRAR_OPERATING_STATUS), operationalRegistrarsQuery);
|
||||||
|
|
||||||
String dnsCountsQuery =
|
String dnsCountsQuery = dnsCountQueryCoordinator.createQuery();
|
||||||
SqlTemplate.create(getQueryFromFile("dns_counts.sql")).build();
|
|
||||||
queriesBuilder.put(getTableName(DNS_COUNTS), dnsCountsQuery);
|
queriesBuilder.put(getTableName(DNS_COUNTS), dnsCountsQuery);
|
||||||
|
|
||||||
// Convert reportingMonth into YYYYMMDD format for Bigquery table partition pattern-matching.
|
// Convert reportingMonth into YYYYMMDD format for Bigquery table partition pattern-matching.
|
||||||
|
@ -133,7 +137,6 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
||||||
return queriesBuilder.build();
|
return queriesBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns the table name of the query, suffixed with the yearMonth in _yyyyMM format. */
|
/** Returns the table name of the query, suffixed with the yearMonth in _yyyyMM format. */
|
||||||
private String getTableName(String queryName) {
|
private String getTableName(String queryName) {
|
||||||
return String.format("%s_%s", queryName, DateTimeFormat.forPattern("yyyyMM").print(yearMonth));
|
return String.format("%s_%s", queryName, DateTimeFormat.forPattern("yyyyMM").print(yearMonth));
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2018 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.reporting.icann;
|
||||||
|
|
||||||
|
import com.google.common.io.Resources;
|
||||||
|
import google.registry.util.ResourceUtils;
|
||||||
|
import google.registry.util.SqlTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DNS Count query for the basic case.
|
||||||
|
*/
|
||||||
|
public class BasicDnsCountQueryCoordinator implements DnsCountQueryCoordinator {
|
||||||
|
|
||||||
|
BasicDnsCountQueryCoordinator(DnsCountQueryCoordinator.Params params) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createQuery() {
|
||||||
|
return SqlTemplate.create(
|
||||||
|
ResourceUtils.readResourceUtf8(
|
||||||
|
Resources.getResource(this.getClass(), "sql/" + "dns_counts.sql")))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepareForQuery() throws Exception {}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright 2018 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.reporting.icann;
|
||||||
|
|
||||||
|
import google.registry.bigquery.BigqueryConnection;
|
||||||
|
import org.joda.time.YearMonth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methods for preparing and querying DNS statistics.
|
||||||
|
*
|
||||||
|
* <p>DNS systems may have different ways of providing this information, so it's useful to
|
||||||
|
* modularize this.
|
||||||
|
*
|
||||||
|
* <p>Derived classes must provide a constructor that accepts a
|
||||||
|
* {@link google.registry.reporting.icann.DnsCountQueryCoordinator.Params}. To override this,
|
||||||
|
* define dnsCountQueryCoordinatorClass in your config file.
|
||||||
|
*/
|
||||||
|
public interface DnsCountQueryCoordinator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to carry parameters for a new coordinator.
|
||||||
|
*
|
||||||
|
* If your report query requires any additional parameters, add them here.
|
||||||
|
*/
|
||||||
|
public class Params {
|
||||||
|
public BigqueryConnection bigquery;
|
||||||
|
|
||||||
|
/** The year and month of the report. */
|
||||||
|
public YearMonth yearMonth;
|
||||||
|
|
||||||
|
/** The Google Cloud project id. */
|
||||||
|
public String projectId;
|
||||||
|
|
||||||
|
public Params(BigqueryConnection bigquery, YearMonth yearMonth, String projectId) {
|
||||||
|
this.bigquery = bigquery;
|
||||||
|
this.yearMonth = yearMonth;
|
||||||
|
this.projectId = projectId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates the string used to query bigtable for DNS count information. */
|
||||||
|
String createQuery();
|
||||||
|
|
||||||
|
/** Do any necessry preparation for the DNS query. */
|
||||||
|
void prepareForQuery() throws Exception;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2018 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.reporting.icann;
|
||||||
|
|
||||||
|
import static google.registry.util.TypeUtils.getClassFromString;
|
||||||
|
import static google.registry.util.TypeUtils.instantiate;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
import google.registry.bigquery.BigqueryConnection;
|
||||||
|
import google.registry.config.RegistryConfig.Config;
|
||||||
|
import org.joda.time.YearMonth;
|
||||||
|
|
||||||
|
/** Dagger module to provide the DnsCountQueryCoordinator. */
|
||||||
|
@Module
|
||||||
|
public class DnsCountQueryCoordinatorModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
static DnsCountQueryCoordinator provideDnsCountQueryCoordinator(
|
||||||
|
@Config("dnsCountQueryCoordinatorClass") String customClass,
|
||||||
|
BigqueryConnection bigquery,
|
||||||
|
YearMonth yearMonth,
|
||||||
|
@Config("projectId") String projectId) {
|
||||||
|
DnsCountQueryCoordinator.Params params =
|
||||||
|
new DnsCountQueryCoordinator.Params(bigquery, yearMonth, projectId);
|
||||||
|
DnsCountQueryCoordinator result =
|
||||||
|
instantiate(getClassFromString(customClass, DnsCountQueryCoordinator.class), params);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,6 +83,10 @@ public class IcannReportingStager {
|
||||||
QueryBuilder queryBuilder =
|
QueryBuilder queryBuilder =
|
||||||
(reportType == ReportType.ACTIVITY) ? activityQueryBuilder : transactionsQueryBuilder;
|
(reportType == ReportType.ACTIVITY) ? activityQueryBuilder : transactionsQueryBuilder;
|
||||||
|
|
||||||
|
if (reportType == ReportType.ACTIVITY) {
|
||||||
|
// Prepare for the DNS count query, which may have special needs.
|
||||||
|
activityQueryBuilder.prepareForQuery();
|
||||||
|
}
|
||||||
|
|
||||||
ImmutableMap<String, String> viewQueryMap = queryBuilder.getViewQueryMap();
|
ImmutableMap<String, String> viewQueryMap = queryBuilder.getViewQueryMap();
|
||||||
// Generate intermediary views
|
// Generate intermediary views
|
||||||
|
|
|
@ -56,6 +56,22 @@ public class TypeUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a class with the specified constructor argument.
|
||||||
|
*
|
||||||
|
* <p>Because we use arg1's type to lookup the constructor, this only works if arg1's class is
|
||||||
|
* exactly the same type as the constructor argument. Subtypes are not allowed.
|
||||||
|
*/
|
||||||
|
public static <T, U> T instantiate(Class<? extends T> clazz, U arg1) {
|
||||||
|
checkArgument(Modifier.isPublic(clazz.getModifiers()),
|
||||||
|
"AppEngine's custom security manager won't let us reflectively access non-public types");
|
||||||
|
try {
|
||||||
|
return clazz.getConstructor(arg1.getClass()).newInstance(arg1);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the class referred to by a fully qualified class name string.
|
* Returns the class referred to by a fully qualified class name string.
|
||||||
*
|
*
|
||||||
|
|
|
@ -31,6 +31,10 @@ public class ActivityReportingQueryBuilderTest {
|
||||||
ActivityReportingQueryBuilder queryBuilder = new ActivityReportingQueryBuilder();
|
ActivityReportingQueryBuilder queryBuilder = new ActivityReportingQueryBuilder();
|
||||||
queryBuilder.yearMonth = new YearMonth(2017, 9);
|
queryBuilder.yearMonth = new YearMonth(2017, 9);
|
||||||
queryBuilder.projectId = "domain-registry-alpha";
|
queryBuilder.projectId = "domain-registry-alpha";
|
||||||
|
queryBuilder.dnsCountQueryCoordinator =
|
||||||
|
new BasicDnsCountQueryCoordinator(
|
||||||
|
new BasicDnsCountQueryCoordinator.Params(null, queryBuilder.yearMonth,
|
||||||
|
queryBuilder.projectId));
|
||||||
return queryBuilder;
|
return queryBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,5 +67,4 @@ public class ActivityReportingQueryBuilderTest {
|
||||||
.isEqualTo(ReportingTestData.loadFile(testFilename));
|
.isEqualTo(ReportingTestData.loadFile(testFilename));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ public class IcannReportingStagerTest {
|
||||||
ActivityReportingQueryBuilder activityBuilder = new ActivityReportingQueryBuilder();
|
ActivityReportingQueryBuilder activityBuilder = new ActivityReportingQueryBuilder();
|
||||||
activityBuilder.projectId = "test-project";
|
activityBuilder.projectId = "test-project";
|
||||||
activityBuilder.yearMonth = new YearMonth(2017, 6);
|
activityBuilder.yearMonth = new YearMonth(2017, 6);
|
||||||
|
activityBuilder.dnsCountQueryCoordinator = new BasicDnsCountQueryCoordinator(null);
|
||||||
action.activityQueryBuilder = activityBuilder;
|
action.activityQueryBuilder = activityBuilder;
|
||||||
TransactionsReportingQueryBuilder transactionsBuilder = new TransactionsReportingQueryBuilder();
|
TransactionsReportingQueryBuilder transactionsBuilder = new TransactionsReportingQueryBuilder();
|
||||||
transactionsBuilder.projectId = "test-project";
|
transactionsBuilder.projectId = "test-project";
|
||||||
|
|
|
@ -52,4 +52,22 @@ public class TypeUtilsTest {
|
||||||
.hasMessageThat()
|
.hasMessageThat()
|
||||||
.contains("Failed to load class com.fake.company.nonexistent.Class");
|
.contains("Failed to load class com.fake.company.nonexistent.Class");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ExampleClass {
|
||||||
|
String val;
|
||||||
|
|
||||||
|
public ExampleClass(String val) {
|
||||||
|
this.val = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_instantiateWithArg() {
|
||||||
|
Class<ExampleClass> clazz =
|
||||||
|
TypeUtils.getClassFromString(
|
||||||
|
"google.registry.util.TypeUtilsTest$ExampleClass", ExampleClass.class);
|
||||||
|
|
||||||
|
ExampleClass result = TypeUtils.instantiate(clazz, "test");
|
||||||
|
assertThat(result.val).isEqualTo("test");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue