mirror of
https://github.com/google/nomulus.git
synced 2025-05-01 12:37:52 +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
127 lines
4.7 KiB
Java
127 lines
4.7 KiB
Java
// Copyright 2019 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 com.beust.jcommander.Parameter;
|
|
import com.beust.jcommander.Parameters;
|
|
import com.google.common.base.Ascii;
|
|
import com.google.common.collect.ImmutableList;
|
|
import google.registry.export.datastore.DatastoreAdmin;
|
|
import google.registry.export.datastore.Operation;
|
|
import java.util.List;
|
|
import java.util.concurrent.TimeUnit;
|
|
import javax.annotation.Nullable;
|
|
import javax.inject.Inject;
|
|
import org.joda.time.Duration;
|
|
|
|
/**
|
|
* Command that imports an earlier backup into Datastore.
|
|
*
|
|
* <p>This command is part of the Datastore restore process. Please refer to <a
|
|
* href="http://playbooks/domain_registry/procedures/backup-restore-testing.md">the playbook</a> for
|
|
* the entire process.
|
|
*/
|
|
@Parameters(separators = " =", commandDescription = "Imports a backup of the Datastore.")
|
|
public class ImportDatastoreCommand extends ConfirmingCommand {
|
|
|
|
@Parameter(names = "--backup_url", description = "URL to the backup on GCS to be imported.")
|
|
private String backupUrl;
|
|
|
|
@Nullable
|
|
@Parameter(
|
|
names = "--kinds",
|
|
description = "List of entity kinds to be imported. Default is to import all.")
|
|
private List<String> kinds = ImmutableList.of();
|
|
|
|
@Parameter(
|
|
names = "--async",
|
|
description = "If true, command will launch import operation and quit.")
|
|
private boolean async;
|
|
|
|
@Parameter(
|
|
names = "--poll_interval",
|
|
description =
|
|
"Polling interval while waiting for completion synchronously. "
|
|
+ "Value is in ISO-8601 format, e.g., PT10S for 10 seconds.")
|
|
private Duration pollingInterval = Duration.standardSeconds(30);
|
|
|
|
@Parameter(
|
|
names = "--confirm_production_import",
|
|
description = "Set this option to 'PRODUCTION' to confirm import in production environment.")
|
|
private String confirmProductionImport = "";
|
|
|
|
@Inject DatastoreAdmin datastoreAdmin;
|
|
|
|
@Override
|
|
protected String execute() throws Exception {
|
|
RegistryToolEnvironment currentEnvironment = RegistryToolEnvironment.get();
|
|
|
|
// Extra confirmation for running in production
|
|
checkArgument(
|
|
!currentEnvironment.equals(RegistryToolEnvironment.PRODUCTION)
|
|
|| confirmProductionImport.equals("PRODUCTION"),
|
|
"The confirm_production_import option must be set when restoring production environment.");
|
|
|
|
Operation importOperation = datastoreAdmin.importBackup(backupUrl, kinds).execute();
|
|
|
|
String statusCommand =
|
|
String.format(
|
|
"nomulus -e %s get_operation_status %s",
|
|
Ascii.toLowerCase(currentEnvironment.name()), importOperation.getName());
|
|
|
|
if (async) {
|
|
return String.format(
|
|
"Datastore import started. Run this command to check its progress:\n%s",
|
|
statusCommand);
|
|
}
|
|
|
|
System.out.println(
|
|
"Waiting for import to complete.\n"
|
|
+ "You may press Ctrl-C at any time, and use this command to check progress:\n"
|
|
+ statusCommand);
|
|
while (importOperation.isProcessing()) {
|
|
waitInteractively(pollingInterval);
|
|
|
|
importOperation = datastoreAdmin.get(importOperation.getName()).execute();
|
|
|
|
System.out.printf("\n%s\n", importOperation.getProgress());
|
|
}
|
|
return String.format(
|
|
"\nDatastore import %s %s.",
|
|
importOperation.getName(), importOperation.isSuccessful() ? "succeeded" : "failed");
|
|
}
|
|
|
|
@Override
|
|
protected String prompt() {
|
|
return "\nThis command is an intermediate step in the Datastore restore process.\n\n"
|
|
+ "Please read and understand the playbook entry at\n"
|
|
+ " http://playbooks/domain_registry/procedures/backup-restore-testing.md\n"
|
|
+ "before proceeding.\n";
|
|
}
|
|
|
|
/** Prints dots to console at regular interval while waiting. */
|
|
private static void waitInteractively(Duration pollingInterval) throws InterruptedException {
|
|
int sleepSeconds = 2;
|
|
long iterations = (pollingInterval.getStandardSeconds() + sleepSeconds - 1) / sleepSeconds;
|
|
|
|
for (int i = 0; i < iterations; i++) {
|
|
TimeUnit.SECONDS.sleep(sleepSeconds);
|
|
System.out.print('.');
|
|
System.out.flush();
|
|
}
|
|
}
|
|
}
|