Create OT&E entities directly, instead of calling sub-commands

This is in preparation for having a web-console endpoint to create OTE.

In addition - we streamline the code:

- we remove support for different premium lists
- we remove support for different DNS writers - we never want a "real" DnsWriter for OTE
- we remove support of --eap_only, because we don't need it anymore
- We use a single password for all the Registrars

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=225841694
This commit is contained in:
guyben 2018-12-17 09:48:28 -08:00 committed by Michael Muller
parent 1004ef5621
commit 9d6a7ef66a
6 changed files with 904 additions and 488 deletions

View file

@ -0,0 +1,377 @@
// 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.model;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryEnvironment;
import google.registry.model.common.GaeUserIdConverter;
import google.registry.model.pricing.StaticPremiumListPricingEngine;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarContact;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.registry.label.PremiumList;
import google.registry.util.CidrAddressBlock;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Class to help build and persist all the OT&E entities in Datastore.
*
* <p>This includes the TLDs (Registries), Registrars, and the RegistrarContacts that can access the
* web console.
*
* This class is basically a "builder" for the parameters needed to generate the OT&amp;E entities.
* Nothing is created until you call {@link #buildAndPersist}.
*
* Usage example:
*
* <pre> {@code
* OteAccountBuilder.forClientId("example")
* .addContact("contact@email.com") // OPTIONAL
* .setPassword("password") // OPTIONAL
* .setCertificateHash(certificateHash) // OPTIONAL
* .setIpWhitelist(ImmutableList.of("1.1.1.1", "2.2.2.0/24")) // OPTIONAL
* .buildAndPersist();
* }</pre>
*/
public final class OteAccountBuilder {
// Regex: 3-14 lower-case alphanumeric characters or hyphens, the first of which must be a letter.
private static final Pattern REGISTRAR_PATTERN = Pattern.compile("^[a-z][-a-z0-9]{2,13}$");
// Durations are short so that registrars can test with quick transfer (etc.) turnaround.
private static final Duration SHORT_ADD_GRACE_PERIOD = Duration.standardMinutes(60);
private static final Duration SHORT_REDEMPTION_GRACE_PERIOD = Duration.standardMinutes(10);
private static final Duration SHORT_PENDING_DELETE_LENGTH = Duration.standardMinutes(5);
private static final String DEFAULT_PREMIUM_LIST = "default_sandbox_list";
private static final RegistrarAddress DEFAULT_ADDRESS =
new RegistrarAddress.Builder()
.setStreet(ImmutableList.of("e-street"))
.setCity("Neverland")
.setState("NY")
.setCountryCode("US")
.setZip("55555")
.build();
private static final ImmutableSortedMap<DateTime, Money> EAP_FEE_SCHEDULE =
ImmutableSortedMap.of(
new DateTime(0),
Money.of(CurrencyUnit.USD, 0),
DateTime.parse("2018-03-01T00:00:00Z"),
Money.of(CurrencyUnit.USD, 100),
DateTime.parse("2030-03-01T00:00:00Z"),
Money.of(CurrencyUnit.USD, 0));
private final ImmutableMap<String, String> clientIdToTld;
private final Registry sunriseTld;
private final Registry landrushTld;
private final Registry gaTld;
private final Registry eapTld;
private final ImmutableList.Builder<RegistrarContact> contactsBuilder =
new ImmutableList.Builder<>();
private ImmutableList<Registrar> registrars;
private boolean replaceExisting = false;
private OteAccountBuilder(String baseClientId) {
checkState(
RegistryEnvironment.get() != RegistryEnvironment.PRODUCTION,
"Can't setup OT&E in production");
clientIdToTld = createClientIdToTldMap(baseClientId);
sunriseTld =
createTld(
baseClientId + "-sunrise", TldState.START_DATE_SUNRISE, null, null, null, false, 0);
landrushTld =
createTld(baseClientId + "-landrush", TldState.LANDRUSH, null, null, null, false, 1);
gaTld =
createTld(
baseClientId + "-ga",
TldState.GENERAL_AVAILABILITY,
SHORT_ADD_GRACE_PERIOD,
SHORT_REDEMPTION_GRACE_PERIOD,
SHORT_PENDING_DELETE_LENGTH,
false,
2);
eapTld =
createTld(
baseClientId + "-eap",
TldState.GENERAL_AVAILABILITY,
SHORT_ADD_GRACE_PERIOD,
SHORT_REDEMPTION_GRACE_PERIOD,
SHORT_PENDING_DELETE_LENGTH,
true,
3);
registrars =
clientIdToTld.keySet().stream()
.map(OteAccountBuilder::createRegistrar)
.collect(toImmutableList());
}
/**
* Creates an OteAccountBuilder for the given base client ID.
*
* @param baseClientId the base clientId which will help name all the entities we create. Normally
* is the same as the "prod" clientId designated for this registrar.
*/
public static OteAccountBuilder forClientId(String baseClientId) {
return new OteAccountBuilder(baseClientId);
}
/**
* Set whether to replace any conflicting existing entities.
*
* <p>If true, any existing entity that conflicts with the entities we want to create will be
* replaced with the newly created data.
*
* <p>If false, encountering an existing entity that conflicts with one we want to create will
* throw an exception during {@link #buildAndPersist}.
*
* <p>NOTE that if we fail, no entities are created (the creation is atomic).
*
* <p>Default is false (failing if entities exist)
*/
public OteAccountBuilder setReplaceExisting(boolean replaceExisting) {
this.replaceExisting = replaceExisting;
return this;
}
/**
* Adds a RegistrarContact with Web Console access.
*
* <p>NOTE: can be called more than once, adding multiple contacts. Each contact will have access
* to all OT&amp;E Registrars.
*
* @param email the contact email that will have web-console access to all the Registrars. Must be
* from "our G Suite domain" (we have to be able to get its GaeUserId)
*/
public OteAccountBuilder addContact(String email) {
String gaeUserId =
checkNotNull(
GaeUserIdConverter.convertEmailAddressToGaeUserId(email),
"Email address %s is not associated with any GAE ID",
email);
registrars.forEach(
registrar -> contactsBuilder.add(createRegistrarContact(email, gaeUserId, registrar)));
return this;
}
/**
* Apply a function on all the OT&amp;E Registrars.
*
* <p>Use this to set up registrar fields.
*
* <p>NOTE: DO NOT change anything that would affect the {@link Key#create} result on Registrars.
* If you want to make this function public, add a check that the Key.create on the registrars
* hasn't changed.
*
* @param func a function setting the requested fields on Registrar Builders. Will be applied to
* all the Registrars.
*/
private OteAccountBuilder transformRegistrars(
Function<Registrar.Builder, Registrar.Builder> func) {
registrars =
registrars.stream()
.map(Registrar::asBuilder)
.map(func)
.map(Registrar.Builder::build)
.collect(toImmutableList());
return this;
}
/** Sets the EPP login password for all the OT&amp;E Registrars. */
public OteAccountBuilder setPassword(String password) {
return transformRegistrars(builder -> builder.setPassword(password));
}
/** Sets the client certificate hash to all the OT&amp;E Registrars. */
public OteAccountBuilder setCertificateHash(String certHash) {
return transformRegistrars(builder -> builder.setClientCertificateHash(certHash));
}
/** Sets the client certificate to all the OT&amp;E Registrars. */
public OteAccountBuilder setCertificate(String asciiCert, DateTime now) {
return transformRegistrars(builder -> builder.setClientCertificate(asciiCert, now));
}
/** Sets the IP whitelist to all the OT&amp;E Registrars. */
public OteAccountBuilder setIpWhitelist(Collection<String> ipWhitelist) {
ImmutableList<CidrAddressBlock> ipAddressWhitelist =
ipWhitelist.stream().map(CidrAddressBlock::create).collect(toImmutableList());
return transformRegistrars(builder -> builder.setIpAddressWhitelist(ipAddressWhitelist));
}
/**
* Persists all the OT&amp;E entities to datastore.
*
* @return map from the new clientIds created to the new TLDs they have access to. Can be used to
* go over all the newly created Registrars / Registries / RegistrarContacts if any
* post-creation work is needed.
*/
public ImmutableMap<String, String> buildAndPersist() {
// save all the entitiesl in a single transaction
ofy().transact(this::saveAllEntities);
return clientIdToTld;
}
/**
* Return map from the OT&amp;E clientIds we will create to the new TLDs they will have access to.
*/
public ImmutableMap<String, String> getClientIdToTldMap() {
return clientIdToTld;
}
/** Saves all the OT&amp;E entities we created. */
private void saveAllEntities() {
ofy().assertInTransaction();
ImmutableList<Registry> registries = ImmutableList.of(sunriseTld, landrushTld, gaTld, eapTld);
ImmutableList<RegistrarContact> contacts = contactsBuilder.build();
if (!replaceExisting) {
ImmutableList<Key<ImmutableObject>> keys =
Streams.concat(registries.stream(), registrars.stream(), contacts.stream())
.map(Key::create)
.collect(toImmutableList());
Set<Key<ImmutableObject>> existingKeys = ofy().load().keys(keys).keySet();
checkState(
existingKeys.isEmpty(),
"Found existing object(s) conflicting with OT&E objects: %s",
existingKeys);
}
// Save the Registries (TLDs) first
ofy().save().entities(registries).now();
// Now we can set the allowedTlds for the registrars
registrars = registrars.stream().map(this::addAllowedTld).collect(toImmutableList());
// and we can save the registrars and contacts!
ofy().save().entities(registrars);
ofy().save().entities(contacts);
}
private Registrar addAllowedTld(Registrar registrar) {
String tld = clientIdToTld.get(registrar.getClientId());
if (registrar.getAllowedTlds().contains(tld)) {
return registrar;
}
return registrar
.asBuilder()
.setAllowedTldsUncached(Sets.union(registrar.getAllowedTlds(), ImmutableSet.of(tld)))
.build();
}
private static Registry createTld(
String tldName,
TldState initialTldState,
Duration addGracePeriod,
Duration redemptionGracePeriod,
Duration pendingDeleteLength,
boolean isEarlyAccess,
int roidSuffix) {
String tldNameAlphaNumerical = tldName.replaceAll("[^a-z0-9]", "");
Optional<PremiumList> premiumList = PremiumList.getUncached(DEFAULT_PREMIUM_LIST);
checkState(premiumList.isPresent(), "Couldn't find premium list %s.", DEFAULT_PREMIUM_LIST);
Registry.Builder builder =
new Registry.Builder()
.setTldStr(tldName)
.setPremiumPricingEngine(StaticPremiumListPricingEngine.NAME)
.setTldStateTransitions(ImmutableSortedMap.of(START_OF_TIME, initialTldState))
.setDnsWriters(ImmutableSet.of("VoidDnsWriter"))
.setPremiumList(premiumList.get())
.setRoidSuffix(
String.format(
"%S%X",
tldNameAlphaNumerical.substring(0, Math.min(tldNameAlphaNumerical.length(), 7)),
roidSuffix));
if (addGracePeriod != null) {
builder.setAddGracePeriodLength(addGracePeriod);
}
if (pendingDeleteLength != null) {
builder.setPendingDeleteLength(pendingDeleteLength);
}
if (redemptionGracePeriod != null) {
builder.setRedemptionGracePeriodLength(redemptionGracePeriod);
}
if (isEarlyAccess) {
builder.setEapFeeSchedule(EAP_FEE_SCHEDULE);
}
return builder.build();
}
/**
* Creates the Registrar without the allowedTlds set - because we can't set allowedTlds before the
* TLD is saved.
*/
private static Registrar createRegistrar(String registrarName) {
return new Registrar.Builder()
.setClientId(registrarName)
.setRegistrarName(registrarName)
.setType(Registrar.Type.OTE)
.setLocalizedAddress(DEFAULT_ADDRESS)
.setEmailAddress("foo@neverland.com")
.setFaxNumber("+1.2125550100")
.setPhoneNumber("+1.2125550100")
.setIcannReferralEmail("nightmare@registrar.test")
.setState(Registrar.State.ACTIVE)
.build();
}
private static RegistrarContact createRegistrarContact(
String email, String gaeUserId, Registrar registrar) {
return new RegistrarContact.Builder()
.setParent(registrar)
.setName(email)
.setEmailAddress(email)
.setGaeUserId(gaeUserId)
.build();
}
/** Returns the ClientIds of the OT&amp;E, with the TLDs each has access to. */
private static ImmutableMap<String, String> createClientIdToTldMap(String baseClientId) {
checkArgument(
REGISTRAR_PATTERN.matcher(baseClientId).matches(),
"Invalid registrar name: %s",
baseClientId);
return new ImmutableMap.Builder<String, String>()
.put(baseClientId + "-1", baseClientId + "-sunrise")
.put(baseClientId + "-2", baseClientId + "-landrush")
.put(baseClientId + "-3", baseClientId + "-ga")
.put(baseClientId + "-4", baseClientId + "-ga")
.put(baseClientId + "-5", baseClientId + "-eap")
.build();
}
}

View file

@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap;
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static com.google.common.collect.Ordering.natural;
@ -68,6 +69,7 @@ import google.registry.model.UpdateAutoTimestamp;
import google.registry.model.annotations.ReportedOn;
import google.registry.model.common.EntityGroupRoot;
import google.registry.model.registrar.Registrar.BillingAccountEntry.CurrencyMapper;
import google.registry.model.registry.Registry;
import google.registry.util.CidrAddressBlock;
import google.registry.util.NonFinalForTesting;
import java.security.MessageDigest;
@ -704,6 +706,28 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
return this;
}
/**
* Same as {@link #setAllowedTlds}, but doesn't use the cache to check if the TLDs exist.
*
* <p>This should be used if the TLD we want to set is persisted in the same transaction -
* meaning its existence can't be cached before we need to save the Registrar.
*
* <p>We can still only set the allowedTld AFTER we saved the Registry entity. Make sure to call
* {@code .now()} when saving the Registry entity to make sure it's actually saved before trying
* to set the allowed TLDs.
*/
public Builder setAllowedTldsUncached(Set<String> allowedTlds) {
ImmutableSet<Key<Registry>> newTldKeys =
Sets.difference(allowedTlds, getInstance().getAllowedTlds()).stream()
.map(tld -> Key.create(getCrossTldKey(), Registry.class, tld))
.collect(toImmutableSet());
Set<Key<Registry>> missingTldKeys =
Sets.difference(newTldKeys, ofy().load().keys(newTldKeys).keySet());
checkArgument(missingTldKeys.isEmpty(), "Trying to set nonexisting TLDs: %s", missingTldKeys);
getInstance().allowedTlds = ImmutableSortedSet.copyOf(allowedTlds);
return this;
}
public Builder setClientCertificate(String clientCertificate, DateTime now) {
clientCertificate = emptyToNull(clientCertificate);
String clientCertificateHash = calculateHash(clientCertificate);

View file

@ -15,69 +15,30 @@
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 static java.nio.charset.StandardCharsets.US_ASCII;
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 com.google.common.collect.ImmutableMap;
import com.google.common.io.MoreFiles;
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.model.OteAccountBuilder;
import google.registry.tools.params.PathParameter;
import google.registry.util.Clock;
import google.registry.util.StringGenerator;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/** Composite command to set up OT&E TLDs and accounts. */
@Parameters(separators = " =", commandDescription = "Set up OT&E TLDs and registrars")
final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemoteApi {
// Regex: 3-14 alphanumeric characters or hyphens, the first of which must be a letter.
private static final Pattern REGISTRAR_PATTERN = Pattern.compile("^[a-z][-a-z0-9]{2,13}$");
private static final int PASSWORD_LENGTH = 16;
// Durations are short so that registrars can test with quick transfer (etc.) turnaround.
private static final Duration SHORT_ADD_GRACE_PERIOD = Duration.standardMinutes(60);
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),
Money.of(CurrencyUnit.USD, 0),
DateTime.parse("2018-03-01T00:00:00Z"),
Money.of(CurrencyUnit.USD, 100),
DateTime.parse("2022-03-01T00:00:00Z"),
Money.of(CurrencyUnit.USD, 0));
private static final String DEFAULT_PREMIUM_LIST = "default_sandbox_list";
@Inject
@Named("dnsWriterNames")
Set<String> validDnsWriterNames;
@Parameter(
names = {"-r", "--registrar"},
description =
@ -101,7 +62,7 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
names = {"--email"},
description =
"the registrar's account to use for console access. "
+ "Must be on the registry's G-Suite domain.",
+ "Must be on the registry's G Suite domain.",
required = true)
private String email;
@ -121,252 +82,83 @@ final class SetupOteCommand extends ConfirmingCommand implements CommandWithRemo
private String certHash;
@Parameter(
names = {"--dns_writers"},
description = "comma separated list of DNS writers to use on all TLDs",
required = true
names = {"--overwrite"},
description = "whether to replace existing entities if we encounter any, instead of failing"
)
private List<String> dnsWriters;
@Parameter(
names = {"--premium_list"},
description = "premium list to apply to all TLDs"
)
private String premiumList = DEFAULT_PREMIUM_LIST;
// TODO: (b/74079782) remove this flag once OT&E for .app is complete.
@Parameter(
names = {"--eap_only"},
description = "whether to only create EAP TLD and registrar"
)
private boolean eapOnly = false;
private boolean overwrite = false;
@Inject
@Config("base64StringGenerator")
StringGenerator passwordGenerator;
/**
* Long registrar names are truncated and then have an incrementing digit appended at the end so
* that unique ROID suffixes can be generated for all TLDs for the registrar.
*/
private int roidSuffixCounter = 0;
@Inject Clock clock;
/** 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,
TldState initialTldState,
Duration addGracePeriod,
Duration redemptionGracePeriod,
Duration pendingDeleteLength,
boolean isEarlyAccess) {
CreateTldCommand command = new CreateTldCommand();
command.addGracePeriod = addGracePeriod;
command.dnsWriters = dnsWriters;
command.validDnsWriterNames = validDnsWriterNames;
command.force = force;
command.initialTldState = initialTldState;
command.mainParameters = ImmutableList.of(tldName);
command.pendingDeleteLength = pendingDeleteLength;
command.premiumListName = Optional.of(premiumList);
String tldNameAlphaNumerical = tldName.replaceAll("[^a-z0-9]", "");
command.roidSuffix =
String.format(
"%S%X",
tldNameAlphaNumerical.substring(0, Math.min(tldNameAlphaNumerical.length(), 7)),
roidSuffixCounter++);
command.redemptionGracePeriod = redemptionGracePeriod;
if (isEarlyAccess) {
command.eapFeeSchedule = EAP_FEE_SCHEDULE;
}
runCommand(command);
}
/** Constructs and runs a CreateRegistrarCommand */
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.
command.allowedTlds = ImmutableList.of(tld);
command.registrarName = registrarName;
command.registrarType = Registrar.Type.OTE;
command.password = password;
command.clientCertificateFilename = certFile;
command.clientCertificateHash = certHash;
command.ipWhitelist = ipWhitelist;
command.street = ImmutableList.of("e-street");
command.city = "Neverland";
command.state = "NY";
command.countryCode = "US";
command.zip = "55555";
command.email = Optional.of("foo@neverland.com");
command.fax = Optional.of("+1.2125550100");
command.phone = Optional.of("+1.2125550100");
command.icannReferralEmail = "nightmare@registrar.test";
command.force = force;
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);
}
OteAccountBuilder oteAccountBuilder;
String password;
/** Run any pre-execute command checks */
@Override
protected boolean checkExecutionState() throws Exception {
checkArgument(
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) {
System.err.printf(
"WARNING: Running against %s environment. Are "
+ "you sure you didn\'t mean to run this against sandbox (e.g. \"-e SANDBOX\")?%n",
RegistryEnvironment.get());
warned = true;
}
if (warned && !promptForYes("Proceed despite warnings?")) {
System.out.println("Command aborted.");
return false;
}
protected void init() throws Exception {
checkArgument(
certFile == null ^ certHash == null,
"Must specify exactly one of client certificate file or client certificate hash.");
// Don't wait for create_registrar to fail if it's a bad certificate file.
password = passwordGenerator.createString(PASSWORD_LENGTH);
oteAccountBuilder =
OteAccountBuilder.forClientId(registrar)
.addContact(email)
.setPassword(password)
.setIpWhitelist(ipWhitelist)
.setReplaceExisting(overwrite);
if (certFile != null) {
loadCertificate(certFile.toAbsolutePath());
String asciiCert = MoreFiles.asCharSource(certFile, US_ASCII).read();
// Don't wait for create_registrar to fail if it's a bad certificate file.
loadCertificate(asciiCert);
oteAccountBuilder.setCertificate(asciiCert, clock.nowUtc());
}
if (certHash != null) {
oteAccountBuilder.setCertificateHash(certHash);
}
return true;
}
@Override
protected String prompt() {
// Each underlying command will confirm its own operation as well, so just provide
// a summary of the steps in this command.
if (eapOnly) {
return "Creating TLD:\n"
+ " " + registrar + "-eap\n"
+ "Creating registrar:\n"
+ " " + registrar + "-5 (access to TLD " + registrar + "-eap)\n"
+ "Giving contact access to this registrar:\n"
+ " " + email;
} else {
return "Creating TLDs:\n"
+ " " + registrar + "-sunrise\n"
+ " " + registrar + "-landrush\n"
+ " " + registrar + "-ga\n"
+ " " + registrar + "-eap\n"
+ "Creating registrars:\n"
+ " " + registrar + "-1 (access to TLD " + registrar + "-sunrise)\n"
+ " " + 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)\n"
+ "Giving contact access to these registrars:\n"
+ " " + email;
ImmutableMap<String, String> registrarToTldMap = oteAccountBuilder.getClientIdToTldMap();
StringBuilder builder = new StringBuilder();
builder.append("Creating TLDs:");
registrarToTldMap.values().forEach(tld -> builder.append("\n ").append(tld));
builder.append("\nCreating registrars:");
registrarToTldMap.forEach(
(clientId, tld) ->
builder.append(String.format("\n %s (with access to %s)", clientId, tld)));
builder.append("\nGiving contact access to these registrars:").append("\n ").append(email);
if (RegistryEnvironment.get() != RegistryEnvironment.SANDBOX
&& RegistryEnvironment.get() != RegistryEnvironment.UNITTEST) {
builder.append(
String.format(
"\n\nWARNING: Running against %s environment. Are "
+ "you sure you didn\'t mean to run this against sandbox (e.g. \"-e SANDBOX\")?",
RegistryEnvironment.get()));
}
return builder.toString();
}
@Override
public String execute() throws Exception {
if (!eapOnly) {
createTld(registrar + "-sunrise", TldState.START_DATE_SUNRISE, null, null, null, false);
createTld(registrar + "-landrush", TldState.LANDRUSH, null, null, null, false);
createTld(
registrar + "-ga",
TldState.GENERAL_AVAILABILITY,
SHORT_ADD_GRACE_PERIOD,
SHORT_REDEMPTION_GRACE_PERIOD,
SHORT_PENDING_DELETE_LENGTH,
false);
} else {
// Increase ROID suffix counter to not collide with existing TLDs.
roidSuffixCounter = roidSuffixCounter + 3;
}
createTld(
registrar + "-eap",
TldState.GENERAL_AVAILABILITY,
SHORT_ADD_GRACE_PERIOD,
SHORT_REDEMPTION_GRACE_PERIOD,
SHORT_PENDING_DELETE_LENGTH,
true);
// Storing names and credentials in a list of tuples for later play-back.
List<List<String>> registrars = new ArrayList<>();
if (!eapOnly) {
registrars.add(
ImmutableList.of(
registrar + "-1",
passwordGenerator.createString(PASSWORD_LENGTH),
registrar + "-sunrise"));
registrars.add(
ImmutableList.of(
registrar + "-2",
passwordGenerator.createString(PASSWORD_LENGTH),
registrar + "-landrush"));
registrars.add(
ImmutableList.of(
registrar + "-3",
passwordGenerator.createString(PASSWORD_LENGTH),
registrar + "-ga"));
registrars.add(
ImmutableList.of(
registrar + "-4",
passwordGenerator.createString(PASSWORD_LENGTH),
registrar + "-ga"));
}
registrars.add(
ImmutableList.of(
registrar + "-5", passwordGenerator.createString(PASSWORD_LENGTH), registrar + "-eap"));
for (List<String> r : registrars) {
createRegistrar(r.get(0), r.get(1), r.get(2));
createRegistrarContact(r.get(0));
}
ImmutableMap<String, String> clientIdToTld = oteAccountBuilder.buildAndPersist();
StringBuilder output = new StringBuilder();
output.append("Copy these usernames/passwords back into the onboarding bug:\n\n");
for (List<String> r : registrars) {
output.append("Login: " + r.get(0) + "\n");
output.append("Password: " + r.get(1) + "\n");
output.append("TLD: " + r.get(2) + "\n\n");
}
clientIdToTld.forEach(
(clientId, tld) -> {
output.append(
String.format("Login: %s\nPassword: %s\nTLD: %s\n\n", clientId, password, tld));
});
return output.toString();
}