Resolved merge conflict

This commit is contained in:
Michael Muller 2018-10-31 14:41:05 -04:00
commit 02c75ee37e
237 changed files with 4148 additions and 3993 deletions

View file

@ -15,7 +15,6 @@
package google.registry.tools;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Suppliers.memoize;
import static com.google.common.net.HttpHeaders.X_REQUESTED_WITH;
import static com.google.common.net.MediaType.JSON_UTF_8;
import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX;
@ -27,48 +26,55 @@ import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.CharStreams;
import com.google.common.net.HostAndPort;
import com.google.common.net.MediaType;
import com.google.re2j.Matcher;
import com.google.re2j.Pattern;
import google.registry.security.XsrfTokenManager;
import google.registry.tools.CommandWithConnection.Connection;
import google.registry.config.RegistryConfig;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Map;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.json.simple.JSONValue;
/** An http connection to the appengine server. */
class AppEngineConnection implements Connection {
/**
* An http connection to an appengine server.
*
* <p>By default - connects to the TOOLS service. To create a Connection to another service, call
* the {@link #withService} function.
*/
class AppEngineConnection {
/** Pattern to heuristically extract title tag contents in HTML responses. */
private static final Pattern HTML_TITLE_TAG_PATTERN = Pattern.compile("<title>(.*?)</title>");
@Inject HttpRequestFactory requestFactory;
@Inject AppEngineConnectionFlags flags;
@Inject XsrfTokenManager xsrfTokenManager;
private final Service service;
@Inject
AppEngineConnection() {}
AppEngineConnection() {
service = Service.TOOLS;
}
/**
* Memoized XSRF security token.
*
* <p>Computing this is expensive since it needs to load {@code ServerSecret} so do it once.
*/
private final Supplier<String> xsrfToken =
memoize(() -> xsrfTokenManager.generateToken(getUserId()));
private AppEngineConnection(Service service, HttpRequestFactory requestFactory) {
this.service = service;
this.requestFactory = requestFactory;
}
@Override
public void prefetchXsrfToken() {
// Cause XSRF token to be fetched, and then stay resident in cache (since it's memoized).
xsrfToken.get();
enum Service {
DEFAULT,
TOOLS,
BACKEND,
PUBAPI
}
/** Returns a copy of this connection that talks to a different service. */
public AppEngineConnection withService(Service service) {
return new AppEngineConnection(service, requestFactory);
}
/** Returns the contents of the title tag in the given HTML, or null if not found. */
@ -85,7 +91,8 @@ class AppEngineConnection implements Connection {
private String internalSend(
String endpoint, Map<String, ?> params, MediaType contentType, @Nullable byte[] payload)
throws IOException {
GenericUrl url = new GenericUrl(String.format("%s%s", getServerUrl(), endpoint));
GenericUrl url = new GenericUrl(getServer());
url.setRawPath(endpoint);
url.putAll(params);
HttpRequest request =
(payload != null)
@ -120,23 +127,20 @@ class AppEngineConnection implements Connection {
}
}
// TODO(b/111123862): Rename this to sendPostRequest()
@Override
public String send(String endpoint, Map<String, ?> params, MediaType contentType, byte[] payload)
public String sendPostRequest(
String endpoint, Map<String, ?> params, MediaType contentType, byte[] payload)
throws IOException {
return internalSend(endpoint, params, contentType, checkNotNull(payload, "payload"));
}
@Override
public String sendGetRequest(String endpoint, Map<String, ?> params) throws IOException {
return internalSend(endpoint, params, MediaType.PLAIN_TEXT_UTF_8, null);
}
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> sendJson(String endpoint, Map<String, ?> object) throws IOException {
String response =
send(
sendPostRequest(
endpoint,
ImmutableMap.of(),
JSON_UTF_8,
@ -144,22 +148,17 @@ class AppEngineConnection implements Connection {
return (Map<String, Object>) JSONValue.parse(response.substring(JSON_SAFETY_PREFIX.length()));
}
@Override
public String getServerUrl() {
return (isLocalhost() ? "http://" : "https://") + getServer().toString();
}
HostAndPort getServer() {
return flags.getServer().withDefaultPort(443); // Default to HTTPS port if unspecified.
}
boolean isLocalhost() {
return flags.getServer().getHost().equals("localhost");
}
private String getUserId() {
return isLocalhost()
? UserIdProvider.getTestUserId()
: UserIdProvider.getProdUserId();
public URL getServer() {
switch (service) {
case DEFAULT:
return RegistryConfig.getDefaultServer();
case TOOLS:
return RegistryConfig.getToolsServer();
case BACKEND:
return RegistryConfig.getBackendServer();
case PUBAPI:
return RegistryConfig.getPubapiServer();
}
throw new IllegalStateException("Unknown service: " + service);
}
}

View file

@ -1,63 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.tools;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.net.HostAndPort;
import dagger.Module;
import dagger.Provides;
import google.registry.config.RegistryConfig;
/**
* Class to contain the configuration flags for AppEngineConnection.
*
* <p>This is broken out into its own class to make it cleaner to extract these from the dagger
* module, where these values are injected.
*/
@Parameters(separators = " =")
class AppEngineConnectionFlags {
@Parameter(names = "--server", description = "HOST[:PORT] to which remote commands are sent.")
private HostAndPort server = RegistryConfig.getServer();
/** Provided for testing. */
@VisibleForTesting
AppEngineConnectionFlags(HostAndPort server) {
this.server = server;
}
AppEngineConnectionFlags() {}
HostAndPort getServer() {
return server;
}
@Module
static class FlagsModule {
AppEngineConnectionFlags flags;
FlagsModule(AppEngineConnectionFlags flags) {
this.flags = flags;
}
@Provides
AppEngineConnectionFlags provideAppEngineConnectionFlags() {
return flags;
}
}
}

View file

@ -46,6 +46,7 @@ java_library(
"//java/google/registry/export",
"//java/google/registry/flows",
"//java/google/registry/gcs",
"//java/google/registry/keyring",
"//java/google/registry/keyring/api",
"//java/google/registry/keyring/kms",
"//java/google/registry/loadtest",
@ -69,7 +70,6 @@ java_library(
"@com_google_api_client",
"@com_google_apis_google_api_services_bigquery",
"@com_google_apis_google_api_services_dns",
"@com_google_apis_google_api_services_monitoring",
"@com_google_appengine_api_1_0_sdk",
"@com_google_appengine_remote_api",
"@com_google_appengine_remote_api//:link",
@ -81,8 +81,6 @@ java_library(
"@com_google_guava",
"@com_google_http_client",
"@com_google_http_client_jackson2",
"@com_google_monitoring_client_metrics",
"@com_google_monitoring_client_stackdriver",
"@com_google_oauth_client",
"@com_google_oauth_client_java6",
"@com_google_oauth_client_jetty",

View file

@ -14,30 +14,7 @@
package google.registry.tools;
import com.google.common.net.MediaType;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Nullable;
/** A command that can send HTTP requests to a backend module. */
interface CommandWithConnection extends Command {
/** An http connection to AppEngine. */
interface Connection {
void prefetchXsrfToken();
/** Send a POST request. TODO(mmuller): change to sendPostRequest() */
String send(
String endpoint, Map<String, ?> params, MediaType contentType, @Nullable byte[] payload)
throws IOException;
String sendGetRequest(String endpoint, Map<String, ?> params) throws IOException;
Map<String, Object> sendJson(String endpoint, Map<String, ?> object) throws IOException;
String getServerUrl();
}
void setConnection(Connection connection);
void setConnection(AppEngineConnection connection);
}

View file

@ -25,6 +25,7 @@ import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.net.InternetDomainName;
import com.google.template.soy.data.SoyMapData;
import google.registry.config.RegistryConfig.Config;
import google.registry.tools.soy.CreateAnchorTenantSoyInfo;
import google.registry.util.StringGenerator;
import javax.inject.Inject;
@ -72,6 +73,7 @@ final class CreateAnchorTenantCommand extends MutatingEppToolCommand {
private boolean fee;
@Inject
@Config("base64StringGenerator")
StringGenerator passwordGenerator;
@Override

View file

@ -20,6 +20,7 @@ import static com.google.common.base.Strings.isNullOrEmpty;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.template.soy.data.SoyMapData;
import google.registry.config.RegistryConfig.Config;
import google.registry.tools.params.PhoneNumberParameter;
import google.registry.tools.soy.ContactCreateSoyInfo;
import google.registry.util.StringGenerator;
@ -103,6 +104,7 @@ final class CreateContactCommand extends MutatingEppToolCommand {
private String password;
@Inject
@Config("base64StringGenerator")
StringGenerator passwordGenerator;
private static final int PASSWORD_LENGTH = 16;

View file

@ -23,6 +23,7 @@ import static org.joda.time.DateTimeZone.UTC;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.template.soy.data.SoyMapData;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.pricing.PremiumPricingEngine.DomainPrices;
import google.registry.tools.soy.DomainCreateSoyInfo;
import google.registry.util.StringGenerator;
@ -46,6 +47,7 @@ final class CreateDomainCommand extends CreateOrUpdateDomainCommand
private boolean forcePremiums;
@Inject
@Config("base64StringGenerator")
StringGenerator passwordGenerator;
private static final int PASSWORD_LENGTH = 16;

View file

@ -57,11 +57,11 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
required = true)
Path inputFile;
protected Connection connection;
protected AppEngineConnection connection;
protected int inputLineCount;
@Override
public void setConnection(Connection connection) {
public void setConnection(AppEngineConnection connection) {
this.connection = connection;
}
@ -101,11 +101,9 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
}
// Call the server and get the response data
String response = connection.send(
getCommandPath(),
params.build(),
MediaType.FORM_DATA,
requestBody.getBytes(UTF_8));
String response =
connection.sendPostRequest(
getCommandPath(), params.build(), MediaType.FORM_DATA, requestBody.getBytes(UTF_8));
return extractServerResponse(response);
}

View file

@ -50,10 +50,10 @@ final class CreateRegistrarCommand extends CreateOrUpdateRegistrarCommand
arity = 1)
boolean createGoogleGroups = true;
private Connection connection;
private AppEngineConnection connection;
@Override
public void setConnection(Connection connection) {
public void setConnection(AppEngineConnection connection) {
this.connection = connection;
}

View file

@ -41,10 +41,10 @@ public class CreateRegistrarGroupsCommand extends ConfirmingCommand
private List<Registrar> registrars = new ArrayList<>();
private Connection connection;
private AppEngineConnection connection;
@Override
public void setConnection(Connection connection) {
public void setConnection(AppEngineConnection connection) {
this.connection = connection;
}
@ -66,8 +66,8 @@ public class CreateRegistrarGroupsCommand extends ConfirmingCommand
}
/** Calls the server endpoint to create groups for the specified registrar client id. */
static void executeOnServer(Connection connection, String clientId) throws IOException {
connection.send(
static void executeOnServer(AppEngineConnection connection, String clientId) throws IOException {
connection.sendPostRequest(
CreateGroupsAction.PATH,
ImmutableMap.of(CreateGroupsAction.CLIENT_ID_PARAM, clientId),
MediaType.PLAIN_TEXT_UTF_8,
@ -77,7 +77,7 @@ public class CreateRegistrarGroupsCommand extends ConfirmingCommand
@Override
protected String execute() throws IOException {
for (Registrar registrar : registrars) {
connection.send(
connection.sendPostRequest(
CreateGroupsAction.PATH,
ImmutableMap.of(CreateGroupsAction.CLIENT_ID_PARAM, registrar.getClientId()),
MediaType.PLAIN_TEXT_UTF_8,

View file

@ -22,11 +22,12 @@ import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.net.MediaType;
import google.registry.tools.AppEngineConnection.Service;
import java.util.List;
@Parameters(separators = " =", commandDescription = "Send an HTTP command to the nomulus server.")
class CurlCommand implements CommandWithConnection {
private Connection connection;
private AppEngineConnection connection;
// HTTP Methods that are acceptable for use as values for --method.
public enum Method {
@ -62,8 +63,14 @@ class CurlCommand implements CommandWithConnection {
+ "absent, a GET request is sent.")
private List<String> data;
@Parameter(
names = {"--service"},
description = "Which service to connect to",
required = true)
private Service service;
@Override
public void setConnection(Connection connection) {
public void setConnection(AppEngineConnection connection) {
this.connection = connection;
}
@ -77,12 +84,14 @@ class CurlCommand implements CommandWithConnection {
throw new IllegalArgumentException("You may not specify a body for a get method.");
}
// TODO(b/112315418): Make it possible to address any backend.
AppEngineConnection connectionToService = connection.withService(service);
String response =
(method == Method.GET)
? connection.sendGetRequest(path, ImmutableMap.<String, String>of())
: connection.send(
path, ImmutableMap.<String, String>of(), mimeType,
? connectionToService.sendGetRequest(path, ImmutableMap.<String, String>of())
: connectionToService.sendPostRequest(
path,
ImmutableMap.<String, String>of(),
mimeType,
Joiner.on("&").join(data).getBytes(UTF_8));
System.out.println(response);
}

View file

@ -20,6 +20,7 @@ import com.google.api.client.http.javanet.NetHttpTransport;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import google.registry.config.RegistryConfig;
import javax.inject.Named;
import javax.inject.Provider;
@ -43,9 +44,8 @@ class DefaultRequestFactoryModule {
@Provides
@Named("default")
public HttpRequestFactory provideHttpRequestFactory(
AppEngineConnectionFlags connectionFlags,
Provider<Credential> credentialProvider) {
if (connectionFlags.getServer().getHost().equals("localhost")) {
if (RegistryConfig.areServersLocal()) {
return new NetHttpTransport()
.createRequestFactory(
request -> request

View file

@ -0,0 +1,107 @@
// 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.tools;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Iterables.partition;
import static com.google.common.collect.Streams.stream;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.cmd.Query;
import google.registry.model.domain.token.AllocationToken;
import java.util.List;
/**
* Command to delete unused {@link AllocationToken}s.
*
* <p>Allocation tokens that have been redeemed cannot be deleted. To delete a single allocation
* token, specify the entire token as the prefix.
*/
@Parameters(
separators = " =",
commandDescription = "Deletes the unused AllocationTokens with a given prefix.")
final class DeleteAllocationTokensCommand extends ConfirmingCommand
implements CommandWithRemoteApi {
@Parameter(
names = {"-p", "--prefix"},
description = "Allocation token prefix; if blank, deletes all unused tokens",
required = true)
private String prefix;
@Parameter(
names = {"--with_domains"},
description = "Allow deletion of allocation tokens with specified domains; defaults to false")
boolean withDomains;
@Parameter(
names = {"--dry_run"},
description = "Do not actually delete the tokens; defaults to false")
boolean dryRun;
private static final int BATCH_SIZE = 20;
private static final Joiner JOINER = Joiner.on(", ");
private ImmutableSet<Key<AllocationToken>> tokensToDelete;
@Override
public void init() {
Query<AllocationToken> query =
ofy().load().type(AllocationToken.class).filter("redemptionHistoryEntry", null);
tokensToDelete =
query.keys().list().stream()
.filter(key -> key.getName().startsWith(prefix))
.collect(toImmutableSet());
}
@Override
protected String prompt() {
return String.format(
"Found %d unused tokens starting with '%s' to delete.", tokensToDelete.size(), prefix);
}
@Override
protected String execute() {
long numDeleted =
stream(partition(tokensToDelete, BATCH_SIZE))
.mapToLong(batch -> ofy().transact(() -> deleteBatch(batch)))
.sum();
return String.format("Deleted %d tokens in total.", numDeleted);
}
/** Deletes a (filtered) batch of AllocationTokens and returns how many were deleted. */
private long deleteBatch(List<Key<AllocationToken>> batch) {
// Load the tokens in the same transaction as they are deleted to verify they weren't redeemed
// since the query ran. This also filters out per-domain tokens if they're not to be deleted.
ImmutableSet<AllocationToken> tokensToDelete =
ofy().load().keys(batch).values().stream()
.filter(t -> withDomains || !t.getDomainName().isPresent())
.filter(t -> !t.isRedeemed())
.collect(toImmutableSet());
if (!dryRun) {
ofy().delete().entities(tokensToDelete);
}
System.out.printf(
"%s tokens: %s\n",
dryRun ? "Would delete" : "Deleted",
JOINER.join(batch.stream().map(Key::getName).collect(toImmutableSet())));
return tokensToDelete.size();
}
}

View file

@ -59,7 +59,7 @@ abstract class EppToolCommand extends ConfirmingCommand
private List<XmlEppParameters> commands = new ArrayList<>();
private Connection connection;
private AppEngineConnection connection;
static class XmlEppParameters {
final String clientId;
@ -95,7 +95,7 @@ abstract class EppToolCommand extends ConfirmingCommand
}
@Override
public void setConnection(Connection connection) {
public void setConnection(AppEngineConnection connection) {
this.connection = connection;
}
@ -145,11 +145,13 @@ abstract class EppToolCommand extends ConfirmingCommand
params.put("xml", URLEncoder.encode(command.xml, UTF_8.toString()));
String requestBody =
Joiner.on('&').withKeyValueSeparator("=").join(filterValues(params, Objects::nonNull));
responses.add(nullToEmpty(connection.send(
"/_dr/epptool",
ImmutableMap.<String, String>of(),
MediaType.FORM_DATA,
requestBody.getBytes(UTF_8))));
responses.add(
nullToEmpty(
connection.sendPostRequest(
"/_dr/epptool",
ImmutableMap.<String, String>of(),
MediaType.FORM_DATA,
requestBody.getBytes(UTF_8))));
}
return responses.build();
}

View file

@ -20,10 +20,8 @@ import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.io.CharStreams;
import com.google.common.io.Files;
import google.registry.util.NonFinalForTesting;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
@ -40,14 +38,10 @@ final class ExecuteEppCommand extends MutatingEppToolCommand {
required = true)
String clientId;
@NonFinalForTesting
private static InputStream stdin = System.in;
@Override
protected void initMutatingEppToolCommand() throws IOException {
if (mainParameters.isEmpty()) {
addXmlCommand(
clientId, CharStreams.toString(new InputStreamReader(stdin, UTF_8)));
addXmlCommand(clientId, CharStreams.toString(new InputStreamReader(System.in, UTF_8)));
} else {
for (String command : mainParameters) {
addXmlCommand(clientId, Files.asCharSource(new File(command), UTF_8).read());

View file

@ -31,6 +31,7 @@ import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.domain.token.AllocationToken;
import google.registry.util.NonFinalForTesting;
import google.registry.util.Retrier;
@ -40,16 +41,15 @@ import java.io.IOException;
import java.util.Collection;
import java.util.Deque;
import javax.inject.Inject;
import javax.inject.Named;
/** Command to generate and persist {@link AllocationToken}s. */
@NonFinalForTesting
@Parameters(
separators = " =",
commandDescription =
"Generates and persists the given number of AllocationTokens, printing each token to stdout."
)
public class GenerateAllocationTokensCommand implements CommandWithRemoteApi {
@NonFinalForTesting
class GenerateAllocationTokensCommand implements CommandWithRemoteApi {
@Parameter(
names = {"-p", "--prefix"},
@ -80,7 +80,10 @@ public class GenerateAllocationTokensCommand implements CommandWithRemoteApi {
description = "Do not actually persist the tokens; defaults to false")
boolean dryRun;
@Inject @Named("base58StringGenerator") StringGenerator stringGenerator;
@Inject
@Config("base58StringGenerator")
StringGenerator stringGenerator;
@Inject Retrier retrier;
private static final int BATCH_SIZE = 20;

View file

@ -22,7 +22,7 @@ import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.collect.ImmutableList;
import google.registry.model.domain.DomainResource;
import google.registry.tmch.LordnTask;
import google.registry.tmch.LordnTaskUtils;
import google.registry.tools.params.PathParameter;
import java.io.IOException;
import java.nio.file.Files;
@ -61,26 +61,28 @@ final class GenerateLordnCommand implements CommandWithRemoteApi {
for (DomainResource domain : ofy().load().type(DomainResource.class).filter("tld", tld)) {
String status = " ";
if (domain.getLaunchNotice() == null && domain.getSmdId() != null) {
sunriseCsv.add(LordnTask.getCsvLineForSunriseDomain(domain, domain.getCreationTime()));
sunriseCsv.add(LordnTaskUtils.getCsvLineForSunriseDomain(domain, domain.getCreationTime()));
status = "S";
} else if (domain.getLaunchNotice() != null || domain.getSmdId() != null) {
claimsCsv.add(LordnTask.getCsvLineForClaimsDomain(domain, domain.getCreationTime()));
claimsCsv.add(LordnTaskUtils.getCsvLineForClaimsDomain(domain, domain.getCreationTime()));
status = "C";
}
System.out.printf("%s[%s] ", domain.getFullyQualifiedDomainName(), status);
}
ImmutableList<String> claimsRows = claimsCsv.build();
ImmutableList<String> claimsAll = new ImmutableList.Builder<String>()
.add(String.format("1,%s,%d", now, claimsRows.size()))
.add(LordnTask.COLUMNS_CLAIMS)
.addAll(claimsRows)
.build();
ImmutableList<String> claimsAll =
new ImmutableList.Builder<String>()
.add(String.format("1,%s,%d", now, claimsRows.size()))
.add(LordnTaskUtils.COLUMNS_CLAIMS)
.addAll(claimsRows)
.build();
ImmutableList<String> sunriseRows = sunriseCsv.build();
ImmutableList<String> sunriseAll = new ImmutableList.Builder<String>()
.add(String.format("1,%s,%d", now.plusMillis(1), sunriseRows.size()))
.add(LordnTask.COLUMNS_SUNRISE)
.addAll(sunriseRows)
.build();
ImmutableList<String> sunriseAll =
new ImmutableList.Builder<String>()
.add(String.format("1,%s,%d", now.plusMillis(1), sunriseRows.size()))
.add(LordnTaskUtils.COLUMNS_SUNRISE)
.addAll(sunriseRows)
.build();
Files.write(claimsOutputPath, claimsAll, UTF_8);
Files.write(sunriseOutputPath, sunriseAll, UTF_8);
}

View file

@ -45,10 +45,10 @@ final class GenerateZoneFilesCommand implements CommandWithConnection, CommandWi
validateWith = DateParameter.class)
private DateTime exportDate = DateTime.now(UTC).minus(standardMinutes(2)).withTimeAtStartOfDay();
private Connection connection;
private AppEngineConnection connection;
@Override
public void setConnection(Connection connection) {
public void setConnection(AppEngineConnection connection) {
this.connection = connection;
}
@ -59,10 +59,7 @@ final class GenerateZoneFilesCommand implements CommandWithConnection, CommandWi
"tlds", mainParameters,
"exportTime", exportDate.toString());
Map<String, Object> response = connection.sendJson(GenerateZoneFilesAction.PATH, params);
System.out.printf(
"Job started at %s%s\n",
connection.getServerUrl(),
response.get("jobPath"));
System.out.printf("Job started at %s %s\n", connection.getServer(), response.get("jobPath"));
System.out.println("Output files:");
@SuppressWarnings("unchecked")
List<String> filenames = (List<String>) response.get("filenames");

View file

@ -15,11 +15,14 @@
package google.registry.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.model.registry.Registries.getTldsOfType;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import google.registry.model.registry.Registry.TldType;
import google.registry.tools.server.ListDomainsAction;
import java.util.List;
@ -29,8 +32,7 @@ final class ListDomainsCommand extends ListObjectsCommand {
@Parameter(
names = {"-t", "--tld", "--tlds"},
description = "Comma-delimited list of top-level domain(s) to list second-level domains of.",
required = true)
description = "Comma-delimited list of TLDs to list domains on; defaults to all REAL TLDs.")
private List<String> tlds;
@Parameter(
@ -47,6 +49,10 @@ final class ListDomainsCommand extends ListObjectsCommand {
/** Returns a map of parameters to be sent to the server (in addition to the usual ones). */
@Override
ImmutableMap<String, Object> getParameterMap() {
// Default to all REAL TLDs if not specified.
if (isNullOrEmpty(tlds)) {
tlds = getTldsOfType(TldType.REAL).asList();
}
String tldsParam = Joiner.on(',').join(tlds);
checkArgument(tldsParam.length() < 1024, "Total length of TLDs is too long for URL parameter");
return ImmutableMap.of("tlds", tldsParam, "limit", maxDomains);

View file

@ -54,10 +54,10 @@ abstract class ListObjectsCommand implements CommandWithConnection, CommandWithR
description = "Whether to print full field names in header row (as opposed to aliases)")
private boolean fullFieldNames = false;
private Connection connection;
private AppEngineConnection connection;
@Override
public void setConnection(Connection connection) {
public void setConnection(AppEngineConnection connection) {
this.connection = connection;
}
@ -83,11 +83,9 @@ abstract class ListObjectsCommand implements CommandWithConnection, CommandWithR
}
params.putAll(getParameterMap());
// Call the server and get the response data.
String response = connection.send(
getCommandPath(),
params.build(),
MediaType.PLAIN_TEXT_UTF_8,
new byte[0]);
String response =
connection.sendPostRequest(
getCommandPath(), params.build(), MediaType.PLAIN_TEXT_UTF_8, new byte[0]);
// Parse the returned JSON and make sure it's a map.
Object obj = JSONValue.parse(response.substring(JSON_SAFETY_PREFIX.length()));
if (!(obj instanceof Map<?, ?>)) {

View file

@ -77,10 +77,10 @@ class LoadTestCommand extends ConfirmingCommand
description = "Time to run the load test in seconds.")
int runSeconds = DEFAULT_RUN_SECONDS;
private Connection connection;
private AppEngineConnection connection;
@Override
public void setConnection(Connection connection) {
public void setConnection(AppEngineConnection connection) {
this.connection = connection;
}
@ -127,10 +127,7 @@ class LoadTestCommand extends ConfirmingCommand
.put("runSeconds", runSeconds)
.build();
return connection.send(
LoadTestAction.PATH,
params,
MediaType.PLAIN_TEXT_UTF_8,
new byte[0]);
return connection.sendPostRequest(
LoadTestAction.PATH, params, MediaType.PLAIN_TEXT_UTF_8, new byte[0]);
}
}

View file

@ -1,53 +0,0 @@
// 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.tools;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.monitoring.v3.Monitoring;
import com.google.api.services.monitoring.v3.model.MonitoredResource;
import com.google.monitoring.metrics.MetricWriter;
import com.google.monitoring.metrics.stackdriver.StackdriverWriter;
import dagger.Module;
import dagger.Provides;
import google.registry.config.CredentialModule.DefaultCredential;
import google.registry.config.RegistryConfig.Config;
/** Dagger module for metrics on the client tool. */
@Module
public final class MetricToolModule {
@Provides
static Monitoring provideMonitoring(
@DefaultCredential GoogleCredential credential, @Config("projectId") String projectId) {
return new Monitoring.Builder(
credential.getTransport(), credential.getJsonFactory(), credential)
.setApplicationName(projectId)
.build();
}
@Provides
static MetricWriter provideMetricWriter(
Monitoring monitoringClient,
@Config("projectId") String projectId,
@Config("stackdriverMaxQps") int maxQps,
@Config("stackdriverMaxPointsPerRequest") int maxPointsPerRequest) {
return new StackdriverWriter(
monitoringClient,
projectId,
new MonitoredResource().setType("global"),
maxQps,
maxPointsPerRequest);
}
}

View file

@ -57,19 +57,19 @@ final class RegistrarContactCommand extends MutatingCommand {
@Parameter(
description = "Client identifier of the registrar account.",
required = true)
private List<String> mainParameters;
List<String> mainParameters;
@Parameter(
names = "--mode",
description = "Type of operation you want to perform (LIST, CREATE, UPDATE, or DELETE).",
required = true)
private Mode mode;
Mode mode;
@Nullable
@Parameter(
names = "--name",
description = "Contact name.")
private String name;
String name;
@Nullable
@Parameter(
@ -82,7 +82,7 @@ final class RegistrarContactCommand extends MutatingCommand {
@Parameter(
names = "--email",
description = "Contact email address.")
private String email;
String email;
@Nullable
@Parameter(
@ -105,7 +105,7 @@ final class RegistrarContactCommand extends MutatingCommand {
names = "--allow_console_access",
description = "Enable or disable access to the registrar console for this contact.",
arity = 1)
private Boolean allowConsoleAccess;
Boolean allowConsoleAccess;
@Nullable
@Parameter(
@ -138,7 +138,7 @@ final class RegistrarContactCommand extends MutatingCommand {
validateWith = PathParameter.OutputFile.class)
private Path output = Paths.get("/dev/stdout");
private enum Mode { LIST, CREATE, UPDATE, DELETE }
enum Mode { LIST, CREATE, UPDATE, DELETE }
private static final ImmutableSet<Mode> MODES_REQUIRING_CONTACT_SYNC =
ImmutableSet.of(Mode.CREATE, Mode.UPDATE, Mode.DELETE);

View file

@ -26,19 +26,11 @@ import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.Parameters;
import com.beust.jcommander.ParametersDelegate;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.monitoring.metrics.IncrementableMetric;
import com.google.monitoring.metrics.LabelDescriptor;
import com.google.monitoring.metrics.Metric;
import com.google.monitoring.metrics.MetricPoint;
import com.google.monitoring.metrics.MetricRegistryImpl;
import com.google.monitoring.metrics.MetricWriter;
import google.registry.config.RegistryConfig;
import google.registry.model.ofy.ObjectifyService;
import google.registry.tools.params.ParameterFactory;
import java.io.IOException;
import java.security.Security;
import java.util.Map;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@ -62,14 +54,6 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
description = "Returns all command names.")
private boolean showAllCommands;
@VisibleForTesting
boolean uploadMetrics = true;
// Do not make this final - compile-time constant inlining may interfere with JCommander.
@ParametersDelegate
private AppEngineConnectionFlags appEngineConnectionFlags =
new AppEngineConnectionFlags();
// Do not make this final - compile-time constant inlining may interfere with JCommander.
@ParametersDelegate
@ -85,24 +69,6 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
// "shell".
private boolean isFirstUse = true;
private static final ImmutableSet<LabelDescriptor> LABEL_DESCRIPTORS_FOR_COMMANDS =
ImmutableSet.of(
LabelDescriptor.create("program", "The program used - e.g. nomulus or gtech_tool"),
LabelDescriptor.create("environment", "The environment used - e.g. sandbox"),
LabelDescriptor.create("command", "The command used"),
LabelDescriptor.create("success", "Whether the command succeeded"),
LabelDescriptor.create("shell", "Whether the command was called from the nomulus shell"));
private static final IncrementableMetric commandsCalledCount =
MetricRegistryImpl.getDefault()
.newIncrementableMetric(
"/tools/commands_called",
"Count of tool commands called",
"count",
LABEL_DESCRIPTORS_FOR_COMMANDS);
private MetricWriter metricWriter = null;
Map<String, ? extends Class<? extends Command>> commands;
String programName;
@ -114,7 +80,6 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
Security.addProvider(new BouncyCastleProvider());
component = DaggerRegistryToolComponent.builder()
.flagsModule(new AppEngineConnectionFlags.FlagsModule(appEngineConnectionFlags))
.build();
}
@ -124,13 +89,9 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
// http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ104
@Override
public void run(String[] args) throws Exception {
boolean inShell = !isFirstUse;
isFirstUse = false;
// Create the JCommander instance.
// If we're in the shell, we don't want to update the RegistryCli's parameters (so we give a
// dummy object to update)
JCommander jcommander = new JCommander(inShell ? new Object() : this);
JCommander jcommander = new JCommander(this);
jcommander.addConverterFactory(new ParameterFactory());
jcommander.setProgramName(programName);
@ -149,8 +110,8 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
// Create the "help" and "shell" commands (these are special in that they don't have a default
// constructor).
jcommander.addCommand("help", new HelpCommand(jcommander));
if (!inShell) {
// If we aren't inside a shell, then we want to add the shell command.
if (isFirstUse) {
isFirstUse = false;
ShellCommand shellCommand = new ShellCommand(this);
// We have to build the completions based on the jcommander *before* we add the "shell"
// command - to avoid completion for the "shell" command itself.
@ -192,31 +153,17 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
jcommander.getCommands().get(jcommander.getParsedCommand()).getObjects());
loggingParams.configureLogging(); // Must be called after parameters are parsed.
boolean success = false;
try {
runCommand(command);
success = true;
} catch (AuthModule.LoginRequiredException ex) {
System.err.println("===================================================================");
System.err.println("You must login using 'nomulus login' prior to running this command.");
System.err.println("===================================================================");
} finally {
commandsCalledCount.increment(
programName,
environment.toString(),
command.getClass().getSimpleName(),
String.valueOf(success),
String.valueOf(inShell));
exportMetrics();
}
}
@Override
public void close() {
exportMetrics();
if (metricWriter != null) {
metricWriter = null;
}
if (installer != null) {
installer.uninstall();
installer = null;
@ -233,14 +180,6 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
private void runCommand(Command command) throws Exception {
injectReflectively(RegistryToolComponent.class, component, command);
if (metricWriter == null && uploadMetrics) {
try {
metricWriter = component.metricWriter();
} catch (Exception e) {
System.err.format("Failed to get metricWriter. Got error:\n%s\n\n", e);
uploadMetrics = false;
}
}
if (command instanceof CommandWithConnection) {
((CommandWithConnection) command).setConnection(getConnection());
@ -253,7 +192,7 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
RemoteApiOptions options = new RemoteApiOptions();
options.server(
getConnection().getServer().getHost(), getConnection().getServer().getPort());
if (getConnection().isLocalhost()) {
if (RegistryConfig.areServersLocal()) {
// Use dev credentials for localhost.
options.useDevelopmentServerCredential();
} else {
@ -272,25 +211,6 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
command.run();
}
private void exportMetrics() {
if (metricWriter == null) {
return;
}
try {
for (Metric<?> metric : MetricRegistryImpl.getDefault().getRegisteredMetrics()) {
for (MetricPoint<?> point : metric.getTimestampedValues()) {
metricWriter.write(point);
}
}
metricWriter.flush();
} catch (IOException e) {
System.err.format("Failed to export metrics. Got error:\n%s\n\n", e);
System.err.println("Maybe you need to login? Try calling:");
System.err.println(" gcloud auth application-default login");
}
}
@VisibleForTesting
void setEnvironment(RegistryToolEnvironment environment) {
this.environment = environment;
}

View file

@ -48,6 +48,7 @@ public final class RegistryTool {
.put("create_sandbox_tld", CreateSandboxTldCommand.class)
.put("create_tld", CreateTldCommand.class)
.put("curl", CurlCommand.class)
.put("delete_allocation_tokens", DeleteAllocationTokensCommand.class)
.put("delete_domain", DeleteDomainCommand.class)
.put("delete_host", DeleteHostCommand.class)
.put("delete_premium_list", DeletePremiumListCommand.class)

View file

@ -14,7 +14,6 @@
package google.registry.tools;
import com.google.monitoring.metrics.MetricWriter;
import dagger.Component;
import google.registry.bigquery.BigqueryModule;
import google.registry.config.CredentialModule;
@ -22,17 +21,15 @@ import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.dns.writer.VoidDnsWriterModule;
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.DummyKeyringModule;
import google.registry.keyring.api.KeyModule;
import google.registry.keyring.kms.KmsModule;
import google.registry.rde.RdeModule;
import google.registry.request.Modules.AppIdentityCredentialModule;
import google.registry.request.Modules.DatastoreServiceModule;
import google.registry.request.Modules.GoogleCredentialModule;
import google.registry.request.Modules.Jackson2Module;
import google.registry.request.Modules.NetHttpTransportModule;
import google.registry.request.Modules.URLFetchServiceModule;
import google.registry.request.Modules.UrlFetchTransportModule;
import google.registry.request.Modules.UseAppIdentityCredentialForGoogleApisModule;
import google.registry.request.Modules.UserServiceModule;
import google.registry.util.AppEngineServiceUtilsImpl.AppEngineServiceUtilsModule;
import google.registry.util.SystemClock.SystemClockModule;
@ -49,37 +46,30 @@ import javax.inject.Singleton;
@Singleton
@Component(
modules = {
AppEngineConnectionFlags.FlagsModule.class,
AppEngineServiceUtilsModule.class,
// TODO(b/36866706): Find a way to replace this with a command-line friendly version
AppIdentityCredentialModule.class,
AuthModule.class,
BigqueryModule.class,
ConfigModule.class,
CredentialModule.class,
DatastoreServiceModule.class,
google.registry.keyring.api.DummyKeyringModule.class,
DummyKeyringModule.class,
CloudDnsWriterModule.class,
DefaultRequestFactoryModule.class,
DefaultRequestFactoryModule.RequestFactoryModule.class,
DnsUpdateWriterModule.class,
GoogleCredentialModule.class,
Jackson2Module.class,
KeyModule.class,
KeyringModule.class,
KmsModule.class,
NetHttpTransportModule.class,
RdeModule.class,
RegistryToolModule.class,
SystemClockModule.class,
SystemSleeperModule.class,
URLFetchServiceModule.class,
UrlFetchTransportModule.class,
// TODO(b/36866706): Find a way to replace this with a command-line friendly version
UseAppIdentityCredentialForGoogleApisModule.class,
UserServiceModule.class,
VoidDnsWriterModule.class,
WhoisModule.class,
MetricToolModule.class,
})
interface RegistryToolComponent {
void inject(CheckDomainClaimsCommand command);
@ -118,6 +108,4 @@ interface RegistryToolComponent {
void inject(WhoisQueryCommand command);
AppEngineConnection appEngineConnection();
MetricWriter metricWriter();
}

View file

@ -1,67 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.tools;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import google.registry.util.RandomStringGenerator;
import google.registry.util.StringGenerator;
import google.registry.util.StringGenerator.Alphabets;
import java.security.NoSuchAlgorithmException;
import java.security.ProviderException;
import java.security.SecureRandom;
import javax.inject.Named;
/** Dagger module for Registry Tool. */
@Module
abstract class RegistryToolModule {
@Provides
static RegistryToolEnvironment provideRegistryToolEnvironment() {
return RegistryToolEnvironment.get();
}
@Binds
abstract StringGenerator provideStringGenerator(RandomStringGenerator stringGenerator);
@Provides
static SecureRandom provideSecureRandom() {
try {
return SecureRandom.getInstance("NativePRNG");
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(e);
}
}
@Provides
@Named("alphabetBase64")
static String provideAlphabetBase64() {
return Alphabets.BASE_64;
}
@Provides
@Named("alphabetBase58")
static String provideAlphabetBase58() {
return Alphabets.BASE_58;
}
@Provides
@Named("base58StringGenerator")
static StringGenerator provideBase58StringGenerator(
@Named("alphabetBase58") String alphabet, SecureRandom random) {
return new RandomStringGenerator(alphabet, random);
}
}

View file

@ -15,15 +15,21 @@
package google.registry.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.tools.CommandUtilities.promptForYes;
import static google.registry.util.X509Utils.loadCertificate;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedMap;
import com.google.re2j.Pattern;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.model.common.GaeUserIdConverter;
import google.registry.model.registrar.Registrar;
import google.registry.model.registry.Registry.TldState;
import google.registry.tools.params.PathParameter;
@ -53,6 +59,10 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
private static final Duration SHORT_REDEMPTION_GRACE_PERIOD = Duration.standardMinutes(10);
private static final Duration SHORT_PENDING_DELETE_LENGTH = Duration.standardMinutes(5);
// Whether to prompt the user on command failures. Set to false for testing of these failures.
@VisibleForTesting
static boolean interactive = true;
private static final ImmutableSortedMap<DateTime, Money> EAP_FEE_SCHEDULE =
ImmutableSortedMap.of(
new DateTime(0),
@ -87,6 +97,14 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
)
private List<String> ipWhitelist = new ArrayList<>();
@Parameter(
names = {"--email"},
description =
"the registrar's account to use for console access. "
+ "Must be on the registry's G-Suite domain.",
required = true)
private String email;
@Parameter(
names = {"-c", "--certfile"},
description = "full path to cert file in PEM format (best if on local storage)",
@ -122,7 +140,9 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
)
private boolean eapOnly = false;
@Inject StringGenerator passwordGenerator;
@Inject
@Config("base64StringGenerator")
StringGenerator passwordGenerator;
/**
* Long registrar names are truncated and then have an incrementing digit appended at the end so
@ -130,6 +150,21 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
*/
private int roidSuffixCounter = 0;
/** Runs a command, clearing the cache before and prompting the user on failures. */
private void runCommand(Command command) {
ofy().clearSessionCache();
try {
command.run();
} catch (Exception e) {
System.err.format("Command failed with error %s\n", e);
if (interactive && promptForYes("Continue to next command?")) {
return;
}
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
/** Constructs and runs a CreateTldCommand. */
private void createTld(
String tldName,
@ -137,8 +172,7 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
Duration addGracePeriod,
Duration redemptionGracePeriod,
Duration pendingDeleteLength,
boolean isEarlyAccess)
throws Exception {
boolean isEarlyAccess) {
CreateTldCommand command = new CreateTldCommand();
command.addGracePeriod = addGracePeriod;
command.dnsWriters = dnsWriters;
@ -158,11 +192,11 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
if (isEarlyAccess) {
command.eapFeeSchedule = EAP_FEE_SCHEDULE;
}
command.run();
runCommand(command);
}
/** Constructs and runs a CreateRegistrarCommand */
private void createRegistrar(String registrarName, String password, String tld) throws Exception {
private void createRegistrar(String registrarName, String password, String tld) {
CreateRegistrarCommand command = new CreateRegistrarCommand();
command.mainParameters = ImmutableList.of(registrarName);
command.createGoogleGroups = false; // Don't create Google Groups for OT&E registrars.
@ -183,7 +217,19 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
command.phone = Optional.of("+1.2125550100");
command.icannReferralEmail = "nightmare@registrar.test";
command.force = force;
command.run();
runCommand(command);
}
/** Constructs and runs a RegistrarContactCommand */
private void createRegistrarContact(String registrarName) {
RegistrarContactCommand command = new RegistrarContactCommand();
command.mainParameters = ImmutableList.of(registrarName);
command.mode = RegistrarContactCommand.Mode.CREATE;
command.name = email;
command.email = email;
command.allowConsoleAccess = true;
command.force = force;
runCommand(command);
}
/** Run any pre-execute command checks */
@ -193,6 +239,14 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
REGISTRAR_PATTERN.matcher(registrar).matches(),
"Registrar name is invalid (see usage text for requirements).");
// Make sure the email is "correct" - as in it's a valid email we can convert to gaeId
// There's no need to look at the result - it'll be converted again inside
// RegistrarContactCommand.
checkNotNull(
GaeUserIdConverter.convertEmailAddressToGaeUserId(email),
"Email address %s is not associated with any GAE ID",
email);
boolean warned = false;
if (RegistryEnvironment.get() != RegistryEnvironment.SANDBOX
&& RegistryEnvironment.get() != RegistryEnvironment.UNITTEST) {
@ -227,7 +281,9 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
return "Creating TLD:\n"
+ " " + registrar + "-eap\n"
+ "Creating registrar:\n"
+ " " + registrar + "-5 (access to TLD " + registrar + "-eap)";
+ " " + registrar + "-5 (access to TLD " + registrar + "-eap)\n"
+ "Giving contact access to this registrar:\n"
+ " " + email;
} else {
return "Creating TLDs:\n"
+ " " + registrar + "-sunrise\n"
@ -239,7 +295,9 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
+ " " + registrar + "-2 (access to TLD " + registrar + "-landrush)\n"
+ " " + registrar + "-3 (access to TLD " + registrar + "-ga)\n"
+ " " + registrar + "-4 (access to TLD " + registrar + "-ga)\n"
+ " " + registrar + "-5 (access to TLD " + registrar + "-eap)";
+ " " + registrar + "-5 (access to TLD " + registrar + "-eap)\n"
+ "Giving contact access to these registrars:\n"
+ " " + email;
}
}
@ -297,6 +355,7 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
for (List<String> r : registrars) {
createRegistrar(r.get(0), r.get(1), r.get(2));
createRegistrarContact(r.get(0));
}
StringBuilder output = new StringBuilder();

View file

@ -145,6 +145,80 @@ public class ShellCommand implements Command {
return this;
}
private static class OutputEncapsulator {
private PrintStream orgStdout;
private PrintStream orgStderr;
private EncapsulatingOutputStream encapsulatedOutputStream = null;
private EncapsulatingOutputStream encapsulatedErrorStream = null;
private Exception error;
private OutputEncapsulator() {
orgStdout = System.out;
orgStderr = System.err;
encapsulatedOutputStream = new EncapsulatingOutputStream(System.out, "out: ");
encapsulatedErrorStream = new EncapsulatingOutputStream(System.out, "err: ");
System.setOut(new PrintStream(encapsulatedOutputStream));
System.setErr(new PrintStream(encapsulatedErrorStream));
}
void setError(Exception e) {
error = e;
}
private void restoreOriginalStreams() {
try {
encapsulatedOutputStream.dumpLastLine();
encapsulatedErrorStream.dumpLastLine();
System.setOut(orgStdout);
System.setErr(orgStderr);
if (error != null) {
emitFailure(error);
} else {
emitSuccess();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Emit a success command separator.
*
* <p>Dumps the last line of output prior to doing this.
*/
private void emitSuccess() {
System.out.println(SUCCESS);
System.out.flush();
}
/**
* Emit a failure message obtained from the throwable.
*
* <p>Dumps the last line of output prior to doing this.
*/
private void emitFailure(Throwable e) {
System.out.println(
FAILURE
+ e.getClass().getName()
+ " "
+ e.getMessage().replace("\\", "\\\\").replace("\n", "\\n"));
}
/** Run "func" with output encapsulation. */
static void run(CommandRunner runner, String[] args) {
OutputEncapsulator encapsulator = new OutputEncapsulator();
try {
runner.run(args);
} catch (Exception e) {
encapsulator.setError(e);
} finally {
encapsulator.restoreOriginalStreams();
}
}
}
/** Run the shell until the user presses "Ctrl-D". */
@Override
public void run() {
@ -154,23 +228,6 @@ public class ShellCommand implements Command {
String line;
DateTime lastTime = clock.nowUtc();
while ((line = getLine()) != null) {
PrintStream orgStdout = null;
PrintStream orgStderr = null;
EncapsulatingOutputStream encapsulatedOutputStream = null;
EncapsulatingOutputStream encapsulatedErrorStream = null;
// Wrap standard output and error if requested. We have to do so here in run because the flags
// haven't been processed in the constructor.
if (encapsulateOutput) {
orgStdout = System.out;
orgStderr = System.err;
encapsulatedOutputStream = new EncapsulatingOutputStream(System.out, "out: ");
encapsulatedErrorStream = new EncapsulatingOutputStream(System.out, "err: ");
System.setOut(new PrintStream(encapsulatedOutputStream));
System.setErr(new PrintStream(encapsulatedErrorStream));
}
// Make sure we're not idle for too long. Only relevant when we're "extra careful"
if (!dontExitOnIdle
&& beExtraCareful
@ -184,28 +241,17 @@ public class ShellCommand implements Command {
if (lineArgs.length == 0) {
continue;
}
Exception lastError = null;
try {
System.out.println("Barf!!!");
runner.run(lineArgs);
} catch (Exception e) {
lastError = e;
System.err.println("Got an exception:\n" + e);
}
try {
if (encapsulatedOutputStream != null) {
encapsulatedOutputStream.dumpLastLine();
encapsulatedErrorStream.dumpLastLine();
System.setOut(orgStdout);
System.setErr(orgStderr);
if (lastError == null) {
emitSuccess();
} else {
emitFailure(lastError);
}
// Wrap standard output and error if requested. We have to do so here in run because the flags
// haven't been processed in the constructor.
if (encapsulateOutput) {
OutputEncapsulator.run(runner, lineArgs);
} else {
try {
runner.run(lineArgs);
} catch (Exception e) {
System.err.println("Got an exception:\n" + e);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (!encapsulateOutput) {
@ -244,29 +290,6 @@ public class ShellCommand implements Command {
return resultBuilder.build().toArray(new String[0]);
}
/**
* Emit a success command separator.
*
* <p>Dumps the last line of output prior to doing this.
*/
private void emitSuccess() {
System.out.println(SUCCESS);
System.out.flush();
}
/**
* Emit a failure message obtained from the throwable.
*
* <p>Dumps the last line of output prior to doing this.
*/
private void emitFailure(Throwable e) {
System.out.println(
FAILURE
+ e.getClass().getName()
+ " "
+ e.getMessage().replace("\\", "\\\\").replace("\n", "\\n"));
}
@VisibleForTesting
static class JCommanderCompletor implements Completor {

View file

@ -57,10 +57,10 @@ final class VerifyOteCommand implements CommandWithConnection, CommandWithRemote
description = "Only show a summary of information")
private boolean summarize;
private Connection connection;
private AppEngineConnection connection;
@Override
public void setConnection(Connection connection) {
public void setConnection(AppEngineConnection connection) {
this.connection = connection;
}

View file

@ -2,7 +2,4 @@ handlers = java.util.logging.ConsoleHandler
.level = INFO
com.google.wrappers.base.GoogleInit.level = WARNING
com.google.monitoring.metrics.MetricRegistryImpl.level = WARNING
com.google.monitoring.metrics.MetricReporter.level = WARNING
com.google.monitoring.metrics.MetricExporter.level = WARNING
com.google.monitoring.metrics.stackdriver.StackdriverWriter.level = WARNING