mv com/google/domain/registry google/registry

This change renames directories in preparation for the great package
rename. The repository is now in a broken state because the code
itself hasn't been updated. However this should ensure that git
correctly preserves history for each file.
This commit is contained in:
Justine Tunney 2016-05-13 18:55:08 -04:00
parent a41677aea1
commit 5012893c1d
2396 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,66 @@
// Copyright 2016 The Domain Registry 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 com.google.domain.registry.flows.async;
import static com.google.domain.registry.request.Actions.getPathForAction;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.RetryOptions;
import com.google.appengine.api.taskqueue.TaskHandle;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.domain.registry.config.RegistryEnvironment;
import com.google.domain.registry.mapreduce.MapreduceAction;
import com.google.domain.registry.util.FormattingLogger;
import org.joda.time.Duration;
import java.util.Map.Entry;
/** Utility methods specific to async flows. */
public final class AsyncFlowUtils {
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
@VisibleForTesting
public static final String ASYNC_FLOW_QUEUE_NAME = "flows-async"; // See queue.xml.
private AsyncFlowUtils() {}
/** Enqueues a mapreduce action to perform an async flow operation. */
public static TaskHandle enqueueMapreduceAction(
Class<? extends MapreduceAction> action,
ImmutableMap<String, String> params,
Duration executionDelay) {
Queue queue = QueueFactory.getQueue(ASYNC_FLOW_QUEUE_NAME);
String path = getPathForAction(action);
logger.infofmt("Enqueueing async mapreduce action with path %s and params %s", path, params);
// Aggressively back off if the task fails, to minimize flooding the logs.
RetryOptions retryOptions = RetryOptions.Builder.withMinBackoffSeconds(
RegistryEnvironment.get().config().getAsyncFlowFailureBackoff().getStandardSeconds());
TaskOptions options = TaskOptions.Builder
.withUrl(path)
.retryOptions(retryOptions)
.countdownMillis(executionDelay.getMillis())
.method(Method.GET);
for (Entry<String, String> entry : params.entrySet()) {
options.param(entry.getKey(), entry.getValue());
}
return queue.add(options);
}
}

View file

@ -0,0 +1,58 @@
// Copyright 2016 The Domain Registry 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 com.google.domain.registry.flows.async;
import static com.google.domain.registry.flows.async.DeleteEppResourceAction.PARAM_IS_SUPERUSER;
import static com.google.domain.registry.flows.async.DeleteEppResourceAction.PARAM_REQUESTING_CLIENT_ID;
import static com.google.domain.registry.flows.async.DeleteEppResourceAction.PARAM_RESOURCE_KEY;
import static com.google.domain.registry.flows.async.DnsRefreshForHostRenameAction.PARAM_HOST_KEY;
import static com.google.domain.registry.request.RequestParameters.extractBooleanParameter;
import static com.google.domain.registry.request.RequestParameters.extractRequiredParameter;
import com.google.domain.registry.request.Parameter;
import dagger.Module;
import dagger.Provides;
import javax.servlet.http.HttpServletRequest;
/** Dagger module for the async flows package. */
@Module
public final class AsyncFlowsModule {
@Provides
@Parameter(PARAM_IS_SUPERUSER)
static boolean provideIsSuperuser(HttpServletRequest req) {
return extractBooleanParameter(req, PARAM_IS_SUPERUSER);
}
@Provides
@Parameter(PARAM_REQUESTING_CLIENT_ID)
static String provideRequestingClientId(HttpServletRequest req) {
return extractRequiredParameter(req, PARAM_REQUESTING_CLIENT_ID);
}
@Provides
@Parameter(PARAM_RESOURCE_KEY)
static String provideResourceKey(HttpServletRequest req) {
return extractRequiredParameter(req, PARAM_RESOURCE_KEY);
}
@Provides
@Parameter(PARAM_HOST_KEY)
static String provideHostKey(HttpServletRequest req) {
return extractRequiredParameter(req, PARAM_HOST_KEY);
}
}

View file

@ -0,0 +1,82 @@
// Copyright 2016 The Domain Registry 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 com.google.domain.registry.flows.async;
import static com.google.domain.registry.flows.ResourceFlowUtils.handlePendingTransferOnDelete;
import com.google.domain.registry.model.contact.ContactResource;
import com.google.domain.registry.model.domain.DomainBase;
import com.google.domain.registry.model.domain.ReferenceUnion;
import com.google.domain.registry.model.reporting.HistoryEntry;
import com.google.domain.registry.model.reporting.HistoryEntry.Type;
import com.google.domain.registry.request.Action;
import org.joda.time.DateTime;
import javax.inject.Inject;
/**
* A mapreduce to delete the specified ContactResource, but ONLY if it is not referred to by any
* existing DomainBase entity.
*/
@Action(path = "/_dr/task/deleteContactResource")
public class DeleteContactResourceAction extends DeleteEppResourceAction<ContactResource> {
@Inject
public DeleteContactResourceAction() {
super(
new DeleteContactResourceMapper(),
new DeleteContactResourceReducer());
}
/** An async deletion mapper for {@link ContactResource}. */
public static class DeleteContactResourceMapper extends DeleteEppResourceMapper<ContactResource> {
private static final long serialVersionUID = -5904009575877950342L;
@Override
protected boolean isLinked(
DomainBase domain, ReferenceUnion<ContactResource> targetResourceRef) {
return domain.getReferencedContacts().contains(targetResourceRef);
}
}
/** An async deletion reducer for {@link ContactResource}. */
public static class DeleteContactResourceReducer
extends DeleteEppResourceReducer<ContactResource> {
private static final long serialVersionUID = -7633644054441045215L;
@Override
protected Type getHistoryType(boolean successfulDelete) {
return successfulDelete
? HistoryEntry.Type.CONTACT_DELETE
: HistoryEntry.Type.CONTACT_DELETE_FAILURE;
}
@Override
protected void performDeleteTasks(
ContactResource targetResource,
ContactResource deletedResource,
DateTime deletionTime,
HistoryEntry historyEntryForDelete) {
handlePendingTransferOnDelete(
targetResource,
deletedResource,
deletionTime,
historyEntryForDelete);
}
}
}

View file

@ -0,0 +1,272 @@
// Copyright 2016 The Domain Registry 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 com.google.domain.registry.flows.async;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.domain.registry.flows.ResourceFlowUtils.prepareDeletedResourceAsBuilder;
import static com.google.domain.registry.flows.ResourceFlowUtils.updateForeignKeyIndexDeletionTime;
import static com.google.domain.registry.model.EppResourceUtils.isActive;
import static com.google.domain.registry.model.EppResourceUtils.isDeleted;
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
import static com.google.domain.registry.util.PipelineUtils.createJobPath;
import static com.google.domain.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.appengine.tools.mapreduce.Mapper;
import com.google.appengine.tools.mapreduce.Reducer;
import com.google.appengine.tools.mapreduce.ReducerInput;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
import com.google.domain.registry.mapreduce.MapreduceAction;
import com.google.domain.registry.mapreduce.MapreduceRunner;
import com.google.domain.registry.mapreduce.inputs.EppResourceInputs;
import com.google.domain.registry.mapreduce.inputs.NullInput;
import com.google.domain.registry.model.EppResource;
import com.google.domain.registry.model.annotations.ExternalMessagingName;
import com.google.domain.registry.model.domain.DomainBase;
import com.google.domain.registry.model.domain.ReferenceUnion;
import com.google.domain.registry.model.eppcommon.StatusValue;
import com.google.domain.registry.model.poll.PollMessage;
import com.google.domain.registry.model.reporting.HistoryEntry;
import com.google.domain.registry.request.HttpException.BadRequestException;
import com.google.domain.registry.request.Parameter;
import com.google.domain.registry.request.Response;
import com.google.domain.registry.util.Clock;
import com.google.domain.registry.util.FormattingLogger;
import com.google.domain.registry.util.NonFinalForTesting;
import com.google.domain.registry.util.SystemClock;
import com.google.domain.registry.util.TypeUtils.TypeInstantiator;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.Work;
import org.joda.time.DateTime;
import javax.inject.Inject;
/**
* A mapreduce to delete the specified EPP resource, but ONLY if it is not referred to by any
* existing DomainBase entity.
*/
public abstract class DeleteEppResourceAction<T extends EppResource> implements MapreduceAction {
@NonFinalForTesting
static Clock clock = new SystemClock();
/** The HTTP parameter name used to specify the websafe key of the resource to delete. */
public static final String PARAM_RESOURCE_KEY = "resourceKey";
public static final String PARAM_REQUESTING_CLIENT_ID = "requestingClientId";
public static final String PARAM_IS_SUPERUSER = "superuser";
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
@Inject @Parameter(PARAM_RESOURCE_KEY) String resourceKeyString;
@Inject @Parameter(PARAM_REQUESTING_CLIENT_ID) String requestingClientId;
@Inject @Parameter(PARAM_IS_SUPERUSER) boolean isSuperuser;
@Inject MapreduceRunner mrRunner;
@Inject Response response;
DeleteEppResourceMapper<T> mapper;
DeleteEppResourceReducer<T> reducer;
protected DeleteEppResourceAction(
DeleteEppResourceMapper<T> mapper,
DeleteEppResourceReducer<T> reducer) {
this.mapper = mapper;
this.reducer = reducer;
}
@Override
public void run() {
Key<T> resourceKey = null;
T resource;
try {
resourceKey = Key.create(resourceKeyString);
resource = checkArgumentNotNull(ofy().load().key(resourceKey).now());
} catch (IllegalArgumentException e) {
throw new BadRequestException(resourceKey == null
? "Could not parse key string: " + resourceKeyString
: "Could not load resource for key: " + resourceKey);
}
checkArgument(
resource.getClass().equals(new TypeInstantiator<T>(getClass()){}.getExactType()),
String.format("Cannot delete a %s via this action.", resource.getClass().getSimpleName()));
checkState(
!isDeleted(resource, clock.nowUtc()),
"Resource %s is already deleted.", resource.getForeignKey());
checkState(
resource.getStatusValues().contains(StatusValue.PENDING_DELETE),
"Resource %s is not set as PENDING_DELETE", resource.getForeignKey());
mapper.setTargetResource(resourceKey);
reducer.setClient(requestingClientId, isSuperuser);
logger.infofmt("Executing Delete EPP resource mapreduce for %s", resourceKey);
response.sendJavaScriptRedirect(createJobPath(mrRunner
.setJobName("Check for EPP resource references and then delete")
.setModuleName("backend")
.runMapreduce(
mapper,
reducer,
ImmutableList.of(
// Add an extra shard that maps over a null domain. See the mapper code for why.
new NullInput<DomainBase>(),
EppResourceInputs.createEntityInput(DomainBase.class)))));
}
/**
* A mapper that iterates over all {@link DomainBase} entities.
*
* <p>It emits the target key and {@code true} for domains referencing the target resource. For
* the special input of {@code null} it emits the target key and {@code false}.
*/
public abstract static class DeleteEppResourceMapper<T extends EppResource>
extends Mapper<DomainBase, Key<T>, Boolean> {
private static final long serialVersionUID = -7355145176854995813L;
private DateTime targetResourceUpdateTimestamp;
private Key<T> targetEppResourceKey;
private void setTargetResource(Key<T> targetEppResourceKey) {
this.targetEppResourceKey = targetEppResourceKey;
this.targetResourceUpdateTimestamp =
ofy().load().key(targetEppResourceKey).now().getUpdateAutoTimestamp().getTimestamp();
}
/** Determine whether the target resource is a linked resource on the domain. */
protected abstract boolean isLinked(DomainBase domain, ReferenceUnion<T> targetResourceRef);
@Override
public void map(DomainBase domain) {
// The reducer only runs if at least one value is emitted. We add a null input to the
// mapreduce and always emit 'false' for it to force the reducer to run. We can then emit
// 'true' for linked domains and not emit anything for unlinked domains, which speeds up the
// reducer since it will only receive true keys, of which there will be few (usually none).
if (domain == null) {
emit(targetEppResourceKey, false);
return;
}
// The ReferenceUnion can't be a field on the Mapper, because when a Ref<?> is serialized
// (required for each MapShardTask), it uses the DeadRef version, which contains the Ref's
// value, which isn't serializable. Thankfully, this isn't expensive.
// See: https://github.com/objectify/objectify/blob/master/src/main/java/com/googlecode/objectify/impl/ref/DeadRef.java
if (isActive(domain, targetResourceUpdateTimestamp)
&& isLinked(domain, ReferenceUnion.create(Ref.create(targetEppResourceKey)))) {
emit(targetEppResourceKey, true);
}
}
}
/**
* A reducer that checks if the EPP resource to be deleted is referenced anywhere, and then
* deletes it if not and unmarks it for deletion if so.
*/
public abstract static class DeleteEppResourceReducer<T extends EppResource>
extends Reducer<Key<T>, Boolean, Void> {
private static final long serialVersionUID = 875017002097945151L;
private String requestingClientId;
private boolean isSuperuser;
private void setClient(String requestingClientId, boolean isSuperuser) {
this.requestingClientId = requestingClientId;
this.isSuperuser = isSuperuser;
}
/**
* Determine the proper history entry type for the delete operation, as a function of
* whether or not the delete was successful.
*/
protected abstract HistoryEntry.Type getHistoryType(boolean successfulDelete);
/** Perform any type-specific tasks on the resource to be deleted (and/or its dependencies). */
protected abstract void performDeleteTasks(
T targetResource,
T deletedResource,
DateTime deletionTime,
HistoryEntry historyEntryForDelete);
@Override
public void reduce(final Key<T> key, final ReducerInput<Boolean> values) {
final boolean hasNoActiveReferences = !Iterators.contains(values, true);
logger.infofmt("Processing delete request for %s", key.toString());
String pollMessageText = ofy().transactNew(new Work<String>() {
@Override
@SuppressWarnings("unchecked")
public String run() {
DateTime now = ofy().getTransactionTime();
T targetResource = (T) ofy().load().key(key).now().cloneProjectedAtTime(now);
String resourceName = targetResource.getForeignKey();
// Double-check that the resource is still active and in PENDING_DELETE within the
// transaction.
checkState(
!isDeleted(targetResource, now),
"Resource %s is already deleted.", resourceName);
checkState(
targetResource.getStatusValues().contains(StatusValue.PENDING_DELETE),
"Resource %s is not in PENDING_DELETE.", resourceName);
targetResource = (T) targetResource.asBuilder()
.removeStatusValue(StatusValue.PENDING_DELETE)
.build();
boolean requestedByCurrentOwner =
targetResource.getCurrentSponsorClientId().equals(requestingClientId);
boolean deleteAllowed = hasNoActiveReferences && (requestedByCurrentOwner || isSuperuser);
String resourceTypeName =
targetResource.getClass().getAnnotation(ExternalMessagingName.class).value();
HistoryEntry.Type historyType = getHistoryType(deleteAllowed);
String pollMessageText = deleteAllowed
? String.format("Deleted %s %s.", resourceTypeName, resourceName)
: String.format(
"Can't delete %s %s because %s.",
resourceTypeName,
resourceName,
requestedByCurrentOwner
? "it is referenced by a domain"
: "it was transferred prior to deletion");
HistoryEntry historyEntry = new HistoryEntry.Builder()
.setClientId(requestingClientId)
.setModificationTime(now)
.setType(historyType)
.setParent(key)
.build();
PollMessage.OneTime deleteResultMessage = new PollMessage.OneTime.Builder()
.setClientId(requestingClientId)
.setMsg(pollMessageText)
.setParent(historyEntry)
.setEventTime(now)
.build();
if (deleteAllowed) {
T deletedResource = prepareDeletedResourceAsBuilder(targetResource, now).build();
performDeleteTasks(targetResource, deletedResource, now, historyEntry);
updateForeignKeyIndexDeletionTime(deletedResource);
ofy().save().<Object>entities(deletedResource, historyEntry, deleteResultMessage);
} else {
ofy().save().<Object>entities(targetResource, historyEntry, deleteResultMessage);
}
return pollMessageText;
}
});
logger.infofmt(pollMessageText);
}
}
}

View file

@ -0,0 +1,84 @@
// Copyright 2016 The Domain Registry 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 com.google.domain.registry.flows.async;
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
import com.google.domain.registry.dns.DnsQueue;
import com.google.domain.registry.model.domain.DomainBase;
import com.google.domain.registry.model.domain.ReferenceUnion;
import com.google.domain.registry.model.host.HostResource;
import com.google.domain.registry.model.reporting.HistoryEntry;
import com.google.domain.registry.model.reporting.HistoryEntry.Type;
import com.google.domain.registry.request.Action;
import org.joda.time.DateTime;
import javax.inject.Inject;
/**
* A mapreduce to delete the specified HostResource, but ONLY if it is not referred to by any
* existing DomainBase entity.
*/
@Action(path = "/_dr/task/deleteHostResource")
public class DeleteHostResourceAction extends DeleteEppResourceAction<HostResource> {
@Inject
public DeleteHostResourceAction() {
super(
new DeleteHostResourceMapper(),
new DeleteHostResourceReducer());
}
/** An async deletion mapper for {@link HostResource}. */
public static class DeleteHostResourceMapper extends DeleteEppResourceMapper<HostResource> {
private static final long serialVersionUID = 1941092742903217194L;
@Override
protected boolean isLinked(
DomainBase domain, ReferenceUnion<HostResource> targetResourceRef) {
return domain.getNameservers().contains(targetResourceRef);
}
}
/** An async deletion reducer for {@link HostResource}. */
public static class DeleteHostResourceReducer extends DeleteEppResourceReducer<HostResource> {
private static final long serialVersionUID = 555457935288867324L;
@Override
protected Type getHistoryType(boolean successfulDelete) {
return successfulDelete
? HistoryEntry.Type.HOST_DELETE
: HistoryEntry.Type.HOST_DELETE_FAILURE;
}
@Override
protected void performDeleteTasks(
HostResource targetResource,
HostResource deletedResource,
DateTime deletionTime,
HistoryEntry historyEntryForDelete) {
if (targetResource.getSuperordinateDomain() != null) {
DnsQueue.create().addHostRefreshTask(targetResource.getFullyQualifiedHostName());
ofy().save().entity(
targetResource.getSuperordinateDomain().get().asBuilder()
.removeSubordinateHost(targetResource.getFullyQualifiedHostName())
.build());
}
}
}
}

View file

@ -0,0 +1,110 @@
// Copyright 2016 The Domain Registry 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 com.google.domain.registry.flows.async;
import static com.google.domain.registry.model.EppResourceUtils.isActive;
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
import static com.google.domain.registry.util.PipelineUtils.createJobPath;
import static com.google.domain.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.appengine.tools.mapreduce.Mapper;
import com.google.common.collect.ImmutableList;
import com.google.domain.registry.dns.DnsQueue;
import com.google.domain.registry.mapreduce.MapreduceAction;
import com.google.domain.registry.mapreduce.MapreduceRunner;
import com.google.domain.registry.mapreduce.inputs.EppResourceInputs;
import com.google.domain.registry.model.domain.DomainResource;
import com.google.domain.registry.model.domain.ReferenceUnion;
import com.google.domain.registry.model.host.HostResource;
import com.google.domain.registry.request.Action;
import com.google.domain.registry.request.HttpException.BadRequestException;
import com.google.domain.registry.request.Parameter;
import com.google.domain.registry.request.Response;
import com.google.domain.registry.util.FormattingLogger;
import com.google.domain.registry.util.NonFinalForTesting;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Ref;
import org.joda.time.DateTime;
import javax.inject.Inject;
/**
* Enqueues DNS refreshes for applicable domains following a host rename.
*/
@Action(path = "/_dr/task/dnsRefreshForHostRename")
public class DnsRefreshForHostRenameAction implements MapreduceAction {
/** The HTTP parameter name used to specify the websafe key of the host to rename. */
public static final String PARAM_HOST_KEY = "hostKey";
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
@NonFinalForTesting
static DnsQueue dnsQueue = DnsQueue.create();
@Inject @Parameter(PARAM_HOST_KEY) String hostKeyString;
@Inject MapreduceRunner mrRunner;
@Inject Response response;
@Inject DnsRefreshForHostRenameAction() {}
@Override
public void run() {
Key<HostResource> resourceKey = null;
HostResource host;
try {
resourceKey = Key.create(hostKeyString);
host = checkArgumentNotNull(ofy().load().key(resourceKey).now());
} catch (IllegalArgumentException e) {
throw new BadRequestException(resourceKey == null
? "Could not parse key string: " + hostKeyString
: "Could not load resource for key: " + resourceKey);
}
response.sendJavaScriptRedirect(createJobPath(mrRunner
.setJobName("Enqueue DNS refreshes for domains following a host rename")
.setModuleName("backend")
.runMapOnly(
new DnsRefreshForHostRenameMapper(host),
ImmutableList.of(EppResourceInputs.createEntityInput(DomainResource.class)))));
}
/** Map over domains and refresh the dns of those that referenced this host. */
public static class DnsRefreshForHostRenameMapper extends Mapper<DomainResource, Void, Void> {
private static final long serialVersionUID = -4707015136971008447L;
private final DateTime hostUpdateTime;
private final Key<HostResource> targetHostKey;
DnsRefreshForHostRenameMapper(HostResource host) {
this.targetHostKey = Key.create(host);
this.hostUpdateTime = host.getUpdateAutoTimestamp().getTimestamp();
}
@Override
public final void map(DomainResource domain) {
if (isActive(domain, hostUpdateTime)
&& domain.getNameservers().contains(ReferenceUnion.create(Ref.create(targetHostKey)))) {
try {
dnsQueue.addDomainRefreshTask(domain.getFullyQualifiedDomainName());
logger.infofmt("Enqueued refresh for domain %s", domain.getFullyQualifiedDomainName());
} catch (Throwable t) {
logger.severefmt(t, "Error while refreshing DNS for host rename %s", targetHostKey);
}
}
}
}
}