mirror of
https://github.com/google/nomulus.git
synced 2025-05-01 20:47:52 +02:00
205 lines
10 KiB
Java
205 lines
10 KiB
Java
// 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 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.base.Strings.emptyToNull;
|
|
import static com.google.common.collect.ImmutableList.toImmutableList;
|
|
import static com.google.common.collect.Iterables.transform;
|
|
import static com.google.common.io.BaseEncoding.base16;
|
|
import static google.registry.flows.EppXmlTransformer.unmarshal;
|
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
|
import static google.registry.tools.CommandUtilities.addHeader;
|
|
import static java.util.stream.Collectors.joining;
|
|
|
|
import com.beust.jcommander.Parameter;
|
|
import com.beust.jcommander.Parameters;
|
|
import com.google.common.base.Ascii;
|
|
import com.google.common.base.Splitter;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.template.soy.data.SoyMapData;
|
|
import com.googlecode.objectify.Key;
|
|
import com.googlecode.objectify.VoidWork;
|
|
import com.googlecode.objectify.Work;
|
|
import google.registry.flows.EppException;
|
|
import google.registry.model.domain.DesignatedContact;
|
|
import google.registry.model.domain.DomainApplication;
|
|
import google.registry.model.domain.DomainCommand;
|
|
import google.registry.model.domain.Period;
|
|
import google.registry.model.domain.launch.ApplicationStatus;
|
|
import google.registry.model.domain.launch.LaunchNotice;
|
|
import google.registry.model.eppinput.EppInput;
|
|
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
|
|
import google.registry.model.reporting.HistoryEntry;
|
|
import google.registry.model.smd.SignedMark;
|
|
import google.registry.tools.soy.DomainAllocateSoyInfo;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
|
|
/** Command to allocated a domain from a domain application. */
|
|
@Parameters(separators = " =", commandDescription = "Allocate a domain application")
|
|
final class AllocateDomainCommand extends MutatingEppToolCommand {
|
|
|
|
@Parameter(
|
|
names = "--ids",
|
|
description = "Comma-delimited list of application IDs to update.",
|
|
required = true)
|
|
String ids;
|
|
|
|
private final List<Key<DomainApplication>> applicationKeys = new ArrayList<>();
|
|
|
|
@Override
|
|
protected String postExecute() throws Exception {
|
|
StringBuilder builder = new StringBuilder();
|
|
// Check to see that we allocated everything.
|
|
return builder
|
|
.append(
|
|
ofy()
|
|
.transactNewReadOnly(
|
|
new Work<String>() {
|
|
@Override
|
|
public String run() {
|
|
String failureMessage =
|
|
ofy()
|
|
.load()
|
|
.keys(applicationKeys)
|
|
.values()
|
|
.stream()
|
|
.map(
|
|
application ->
|
|
application.getApplicationStatus()
|
|
== ApplicationStatus.ALLOCATED
|
|
? null
|
|
: application.getFullyQualifiedDomainName())
|
|
.filter(Objects::nonNull)
|
|
.collect(joining("\n"));
|
|
return failureMessage.isEmpty()
|
|
? "ALL SUCCEEDED"
|
|
: addHeader("FAILURES", failureMessage);
|
|
}
|
|
}))
|
|
.toString();
|
|
}
|
|
|
|
/** Extract the registration period from the XML used to create the domain application. */
|
|
private static Period extractPeriodFromXml(byte[] xmlBytes) throws EppException {
|
|
EppInput eppInput = unmarshal(EppInput.class, xmlBytes);
|
|
return ((DomainCommand.Create)
|
|
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
|
|
.getResourceCommand()).getPeriod();
|
|
}
|
|
|
|
@Override
|
|
protected void initMutatingEppToolCommand() {
|
|
checkArgument(superuser, "This command MUST be run as --superuser.");
|
|
setSoyTemplate(DomainAllocateSoyInfo.getInstance(), DomainAllocateSoyInfo.CREATE);
|
|
ofy()
|
|
.transactNewReadOnly(
|
|
new VoidWork() {
|
|
@Override
|
|
public void vrun() {
|
|
Iterable<Key<DomainApplication>> keys =
|
|
transform(
|
|
Splitter.on(',').split(ids),
|
|
applicationId -> Key.create(DomainApplication.class, applicationId));
|
|
for (DomainApplication application : ofy().load().keys(keys).values()) {
|
|
// If the application is already allocated print a warning but do not fail.
|
|
if (application.getApplicationStatus() == ApplicationStatus.ALLOCATED) {
|
|
System.err.printf(
|
|
"Application %s has already been allocated\n", application.getRepoId());
|
|
continue;
|
|
}
|
|
// Ensure domain doesn't already have a final status which it shouldn't be updated
|
|
// from.
|
|
checkState(
|
|
!application.getApplicationStatus().isFinalStatus(),
|
|
"Application has final status %s",
|
|
application.getApplicationStatus());
|
|
try {
|
|
HistoryEntry history =
|
|
checkNotNull(
|
|
ofy()
|
|
.load()
|
|
.type(HistoryEntry.class)
|
|
.ancestor(checkNotNull(application))
|
|
.order("modificationTime")
|
|
.first()
|
|
.now(),
|
|
"Could not find any history entries for domain application %s",
|
|
application.getRepoId());
|
|
String clientTransactionId =
|
|
emptyToNull(history.getTrid().getClientTransactionId());
|
|
Period period = checkNotNull(extractPeriodFromXml(history.getXmlBytes()));
|
|
checkArgument(period.getUnit() == Period.Unit.YEARS);
|
|
ImmutableMap.Builder<String, String> contactsMapBuilder =
|
|
new ImmutableMap.Builder<>();
|
|
for (DesignatedContact contact : application.getContacts()) {
|
|
contactsMapBuilder.put(
|
|
Ascii.toLowerCase(contact.getType().toString()),
|
|
ofy().load().key(contact.getContactKey()).now().getForeignKey());
|
|
}
|
|
LaunchNotice launchNotice = application.getLaunchNotice();
|
|
addSoyRecord(
|
|
application.getCurrentSponsorClientId(),
|
|
new SoyMapData(
|
|
"name", application.getFullyQualifiedDomainName(),
|
|
"period", period.getValue(),
|
|
"nameservers", application.loadNameserverFullyQualifiedHostNames(),
|
|
"registrant",
|
|
ofy().load().key(application.getRegistrant()).now().getForeignKey(),
|
|
"contacts", contactsMapBuilder.build(),
|
|
"authInfo", application.getAuthInfo().getPw().getValue(),
|
|
"smdId",
|
|
application.getEncodedSignedMarks().isEmpty()
|
|
? null
|
|
: unmarshal(
|
|
SignedMark.class,
|
|
application.getEncodedSignedMarks().get(0).getBytes())
|
|
.getId(),
|
|
"applicationRoid", application.getRepoId(),
|
|
"applicationTime", application.getCreationTime().toString(),
|
|
"launchNotice",
|
|
launchNotice == null
|
|
? null
|
|
: ImmutableMap.of(
|
|
"noticeId", launchNotice.getNoticeId().getTcnId(),
|
|
"expirationTime",
|
|
launchNotice.getExpirationTime().toString(),
|
|
"acceptedTime", launchNotice.getAcceptedTime().toString()),
|
|
"dsRecords",
|
|
application
|
|
.getDsData()
|
|
.stream()
|
|
.map(
|
|
dsData ->
|
|
ImmutableMap.of(
|
|
"keyTag", dsData.getKeyTag(),
|
|
"algorithm", dsData.getAlgorithm(),
|
|
"digestType", dsData.getDigestType(),
|
|
"digest", base16().encode(dsData.getDigest())))
|
|
.collect(toImmutableList()),
|
|
"clTrid", clientTransactionId));
|
|
applicationKeys.add(Key.create(application));
|
|
} catch (EppException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|