mirror of
https://github.com/google/nomulus.git
synced 2025-05-02 21:17:50 +02:00
Two commands are being added: - ImportDatastoreCommand starts an async import operation. User may choose to wait until import completes or quit immediately. - GetOperationStatusCommand checks the status of an operation. It may be used to check the status of an operation started by ImportDatastoreCommand. Both commands communicate with Datastore admin api directly, without going through the Registry server. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=228400059
248 lines
7.3 KiB
Java
248 lines
7.3 KiB
Java
// 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.export.datastore;
|
|
|
|
import static com.google.common.base.Preconditions.checkState;
|
|
import static com.google.common.base.Strings.isNullOrEmpty;
|
|
|
|
import com.google.api.client.json.GenericJson;
|
|
import com.google.api.client.util.Key;
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.google.common.collect.ImmutableSet;
|
|
import google.registry.export.datastore.DatastoreAdmin.Get;
|
|
import google.registry.util.Clock;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import javax.annotation.Nullable;
|
|
import org.joda.time.DateTime;
|
|
import org.joda.time.Duration;
|
|
|
|
/**
|
|
* Model object that describes the details of an export or import operation in Cloud Datastore.
|
|
*
|
|
* <p>{@link Operation} instances are parsed from the JSON payload in Datastore response messages.
|
|
*/
|
|
public class Operation extends GenericJson {
|
|
|
|
private static final String STATE_SUCCESS = "SUCCESSFUL";
|
|
private static final String STATE_PROCESSING = "PROCESSING";
|
|
|
|
@Key private String name;
|
|
@Key private Metadata metadata;
|
|
@Key private boolean done;
|
|
|
|
/** For JSON deserialization. */
|
|
public Operation() {}
|
|
|
|
/** Returns the name of this operation, which may be used in a {@link Get} request. */
|
|
public String getName() {
|
|
checkState(name != null, "Name must not be null.");
|
|
return name;
|
|
}
|
|
|
|
public boolean isExport() {
|
|
return !isNullOrEmpty(getExportFolderUrl());
|
|
}
|
|
|
|
public boolean isImport() {
|
|
return !isNullOrEmpty(getMetadata().getInputUrl());
|
|
}
|
|
|
|
public boolean isDone() {
|
|
return done;
|
|
}
|
|
|
|
private String getState() {
|
|
return getMetadata().getCommonMetadata().getState();
|
|
}
|
|
|
|
public boolean isSuccessful() {
|
|
return getState().equals(STATE_SUCCESS);
|
|
}
|
|
|
|
public boolean isProcessing() {
|
|
return getState().equals(STATE_PROCESSING);
|
|
}
|
|
|
|
/**
|
|
* Returns the elapsed time since starting if this operation is still running, or the total
|
|
* running time if this operation has completed.
|
|
*/
|
|
public Duration getRunningTime(Clock clock) {
|
|
return new Duration(
|
|
getStartTime(), getMetadata().getCommonMetadata().getEndTime().orElse(clock.nowUtc()));
|
|
}
|
|
|
|
public DateTime getStartTime() {
|
|
return getMetadata().getCommonMetadata().getStartTime();
|
|
}
|
|
|
|
public ImmutableSet<String> getKinds() {
|
|
return ImmutableSet.copyOf(getMetadata().getEntityFilter().getKinds());
|
|
}
|
|
|
|
/**
|
|
* Returns the URL to the GCS folder that holds the exported data. This folder is created by
|
|
* Datastore and is under the {@code outputUrlPrefix} set to {@linkplain
|
|
* DatastoreAdmin#export(String, java.util.Collection) the export request}.
|
|
*
|
|
* @throws IllegalStateException if this is not an export operation
|
|
*/
|
|
public String getExportFolderUrl() {
|
|
return getMetadata().getOutputUrlPrefix();
|
|
}
|
|
|
|
/**
|
|
* Returns the last segment of the {@linkplain #getExportFolderUrl() export folder URL} which can
|
|
* be used as unique identifier of this export operation. This is a better ID than the {@linkplain
|
|
* #getName() operation name}, which is opaque.
|
|
*
|
|
* @throws IllegalStateException if this is not an export operation
|
|
*/
|
|
public String getExportId() {
|
|
String exportFolderUrl = getExportFolderUrl();
|
|
return exportFolderUrl.substring(exportFolderUrl.lastIndexOf('/') + 1);
|
|
}
|
|
|
|
public String getProgress() {
|
|
StringBuilder result = new StringBuilder();
|
|
Progress progress = getMetadata().getProgressBytes();
|
|
if (progress != null) {
|
|
result.append(
|
|
String.format(" [%s/%s bytes]", progress.workCompleted, progress.workEstimated));
|
|
}
|
|
progress = getMetadata().getProgressEntities();
|
|
if (progress != null) {
|
|
result.append(
|
|
String.format(" [%s/%s entities]", progress.workCompleted, progress.workEstimated));
|
|
}
|
|
if (result.length() == 0) {
|
|
return "Progress: N/A";
|
|
}
|
|
return "Progress:" + result;
|
|
}
|
|
|
|
private Metadata getMetadata() {
|
|
checkState(metadata != null, "Response metadata missing.");
|
|
return metadata;
|
|
}
|
|
|
|
/** Models the common metadata properties of all operations. */
|
|
public static class CommonMetadata extends GenericJson {
|
|
|
|
@Key private String startTime;
|
|
@Key @Nullable private String endTime;
|
|
@Key private String operationType;
|
|
@Key private String state;
|
|
|
|
public CommonMetadata() {}
|
|
|
|
String getOperationType() {
|
|
checkState(!isNullOrEmpty(operationType), "operationType may not be null or empty");
|
|
return operationType;
|
|
}
|
|
|
|
String getState() {
|
|
checkState(!isNullOrEmpty(state), "state may not be null or empty");
|
|
return state;
|
|
}
|
|
|
|
DateTime getStartTime() {
|
|
checkState(startTime != null, "StartTime missing.");
|
|
return DateTime.parse(startTime);
|
|
}
|
|
|
|
Optional<DateTime> getEndTime() {
|
|
return Optional.ofNullable(endTime).map(DateTime::parse);
|
|
}
|
|
}
|
|
|
|
/** Models the metadata of a Cloud Datatore export or import operation. */
|
|
public static class Metadata extends GenericJson {
|
|
@Key("common")
|
|
private CommonMetadata commonMetadata;
|
|
|
|
@Key private Progress progressEntities;
|
|
@Key private Progress progressBytes;
|
|
@Key private EntityFilter entityFilter;
|
|
@Key private String inputUrl;
|
|
@Key private String outputUrlPrefix;
|
|
|
|
public Metadata() {}
|
|
|
|
CommonMetadata getCommonMetadata() {
|
|
checkState(commonMetadata != null, "CommonMetadata field is null.");
|
|
return commonMetadata;
|
|
}
|
|
|
|
public Progress getProgressEntities() {
|
|
return progressEntities;
|
|
}
|
|
|
|
public Progress getProgressBytes() {
|
|
return progressBytes;
|
|
}
|
|
|
|
public EntityFilter getEntityFilter() {
|
|
return entityFilter;
|
|
}
|
|
|
|
public String getInputUrl() {
|
|
return checkUrls().inputUrl;
|
|
}
|
|
|
|
public String getOutputUrlPrefix() {
|
|
return checkUrls().outputUrlPrefix;
|
|
}
|
|
|
|
Metadata checkUrls() {
|
|
checkState(
|
|
isNullOrEmpty(inputUrl) || isNullOrEmpty(outputUrlPrefix),
|
|
"inputUrl and outputUrlPrefix must not be both present");
|
|
checkState(
|
|
!isNullOrEmpty(inputUrl) || !isNullOrEmpty(outputUrlPrefix),
|
|
"inputUrl and outputUrlPrefix must not be both missing");
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/** Progress of an export or import operation. */
|
|
public static class Progress extends GenericJson {
|
|
@Key private long workCompleted;
|
|
@Key private long workEstimated;
|
|
|
|
public Progress() {}
|
|
|
|
long getWorkCompleted() {
|
|
return workCompleted;
|
|
}
|
|
|
|
public long getWorkEstimated() {
|
|
return workEstimated;
|
|
}
|
|
}
|
|
|
|
/** List of {@link Operation Operations}. */
|
|
public static class OperationList extends GenericJson {
|
|
@Key private List<Operation> operations;
|
|
|
|
/** For JSON deserialization. */
|
|
public OperationList() {}
|
|
|
|
ImmutableList<Operation> toList() {
|
|
return ImmutableList.copyOf(operations);
|
|
}
|
|
}
|
|
}
|