001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.backup;
019
020import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_CHECK;
021import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_CHECK_DESC;
022import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_DEBUG;
023import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_DEBUG_DESC;
024import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_OVERWRITE;
025import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_OVERWRITE_DESC;
026import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_SET;
027import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_SET_RESTORE_DESC;
028import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_TABLE;
029import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_TABLE_LIST_DESC;
030import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_TABLE_MAPPING;
031import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_TABLE_MAPPING_DESC;
032import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_YARN_QUEUE_NAME;
033import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_YARN_QUEUE_NAME_RESTORE_DESC;
034
035import java.io.IOException;
036import java.util.List;
037import java.util.Objects;
038import org.apache.commons.lang3.StringUtils;
039import org.apache.hadoop.hbase.TableName;
040import org.apache.hadoop.hbase.backup.impl.BackupManager;
041import org.apache.hadoop.hbase.backup.impl.BackupSystemTable;
042import org.apache.hadoop.hbase.backup.util.BackupUtils;
043import org.apache.hadoop.hbase.client.Connection;
044import org.apache.hadoop.hbase.client.ConnectionFactory;
045import org.apache.hadoop.hbase.logging.Log4jUtils;
046import org.apache.hadoop.hbase.util.AbstractHBaseTool;
047import org.apache.yetus.audience.InterfaceAudience;
048import org.slf4j.Logger;
049import org.slf4j.LoggerFactory;
050
051import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine;
052import org.apache.hbase.thirdparty.org.apache.commons.cli.HelpFormatter;
053
054@InterfaceAudience.Private
055public abstract class AbstractRestoreDriver extends AbstractHBaseTool {
056  protected static final Logger LOG = LoggerFactory.getLogger(AbstractRestoreDriver.class);
057  protected CommandLine cmd;
058
059  protected static final String USAGE_FOOTER = "";
060
061  protected AbstractRestoreDriver() {
062    init();
063  }
064
065  protected void init() {
066    Log4jUtils.disableZkAndClientLoggers();
067  }
068
069  protected abstract int executeRestore(boolean check, TableName[] fromTables, TableName[] toTables,
070    boolean isOverwrite);
071
072  private int parseAndRun() throws IOException {
073    if (!BackupManager.isBackupEnabled(getConf())) {
074      System.err.println(BackupRestoreConstants.ENABLE_BACKUP);
075      return -1;
076    }
077
078    if (cmd.hasOption(OPTION_DEBUG)) {
079      Log4jUtils.setLogLevel("org.apache.hadoop.hbase.backup", "DEBUG");
080    }
081
082    boolean overwrite = cmd.hasOption(OPTION_OVERWRITE);
083    if (overwrite) {
084      LOG.debug("Found overwrite option (-{}) in restore command, "
085        + "will overwrite to existing table if any in the restore target", OPTION_OVERWRITE);
086    }
087
088    boolean check = cmd.hasOption(OPTION_CHECK);
089    if (check) {
090      LOG.debug(
091        "Found check option (-{}) in restore command, will check and verify the dependencies",
092        OPTION_CHECK);
093    }
094
095    if (cmd.hasOption(OPTION_SET) && cmd.hasOption(OPTION_TABLE)) {
096      System.err.printf(
097        "Set name (-%s) and table list (-%s) are mutually exclusive, you can not specify both "
098          + "of them.%n",
099        OPTION_SET, OPTION_TABLE);
100      printToolUsage();
101      return -1;
102    }
103
104    if (!cmd.hasOption(OPTION_SET) && !cmd.hasOption(OPTION_TABLE)) {
105      System.err.printf(
106        "You have to specify either set name (-%s) or table list (-%s) to " + "restore%n",
107        OPTION_SET, OPTION_TABLE);
108      printToolUsage();
109      return -1;
110    }
111
112    if (cmd.hasOption(OPTION_YARN_QUEUE_NAME)) {
113      String queueName = cmd.getOptionValue(OPTION_YARN_QUEUE_NAME);
114      // Set MR job queuename to configuration
115      getConf().set("mapreduce.job.queuename", queueName);
116    }
117
118    String tables;
119    TableName[] sTableArray;
120    TableName[] tTableArray;
121
122    String tableMapping = cmd.getOptionValue(OPTION_TABLE_MAPPING);
123
124    try (final Connection conn = ConnectionFactory.createConnection(conf)) {
125      // Check backup set
126      if (cmd.hasOption(OPTION_SET)) {
127        String setName = cmd.getOptionValue(OPTION_SET);
128        try {
129          tables = getTablesForSet(conn, setName);
130        } catch (IOException e) {
131          System.out.println("ERROR: " + e.getMessage() + " for setName=" + setName);
132          printToolUsage();
133          return -2;
134        }
135        if (tables == null) {
136          System.out
137            .println("ERROR: Backup set '" + setName + "' is either empty or does not exist");
138          printToolUsage();
139          return -3;
140        }
141      } else {
142        tables = cmd.getOptionValue(OPTION_TABLE);
143      }
144
145      sTableArray = BackupUtils.parseTableNames(tables);
146      tTableArray = BackupUtils.parseTableNames(tableMapping);
147
148      if (
149        sTableArray != null && tTableArray != null && (sTableArray.length != tTableArray.length)
150      ) {
151        System.out.println("ERROR: table mapping mismatch: " + tables + " : " + tableMapping);
152        printToolUsage();
153        return -4;
154      }
155    }
156
157    return executeRestore(check, sTableArray, tTableArray, overwrite);
158  }
159
160  @Override
161  protected void addOptions() {
162    addOptNoArg(OPTION_OVERWRITE, OPTION_OVERWRITE_DESC);
163    addOptNoArg(OPTION_CHECK, OPTION_CHECK_DESC);
164    addOptNoArg(OPTION_DEBUG, OPTION_DEBUG_DESC);
165    addOptWithArg(OPTION_SET, OPTION_SET_RESTORE_DESC);
166    addOptWithArg(OPTION_TABLE, OPTION_TABLE_LIST_DESC);
167    addOptWithArg(OPTION_TABLE_MAPPING, OPTION_TABLE_MAPPING_DESC);
168    addOptWithArg(OPTION_YARN_QUEUE_NAME, OPTION_YARN_QUEUE_NAME_RESTORE_DESC);
169  }
170
171  @Override
172  protected void processOptions(CommandLine cmd) {
173    this.cmd = cmd;
174  }
175
176  @Override
177  protected int doWork() throws Exception {
178    return parseAndRun();
179  }
180
181  @Override
182  public int run(String[] args) {
183    Objects.requireNonNull(conf, "Tool configuration is not initialized");
184
185    try {
186      cmd = parseArgs(args);
187    } catch (Exception e) {
188      System.out.println("Error parsing command-line arguments: " + e.getMessage());
189      printToolUsage();
190      return EXIT_FAILURE;
191    }
192
193    if (cmd.hasOption(SHORT_HELP_OPTION) || cmd.hasOption(LONG_HELP_OPTION)) {
194      printToolUsage();
195      return EXIT_FAILURE;
196    }
197
198    processOptions(cmd);
199
200    try {
201      return doWork();
202    } catch (Exception e) {
203      LOG.error("Error running restore tool", e);
204      return EXIT_FAILURE;
205    }
206  }
207
208  protected void printToolUsage() {
209    System.out.println(getUsageString());
210    HelpFormatter helpFormatter = new HelpFormatter();
211    helpFormatter.setLeftPadding(2);
212    helpFormatter.setDescPadding(8);
213    helpFormatter.setWidth(100);
214    helpFormatter.setSyntaxPrefix("Options:");
215    helpFormatter.printHelp(" ", null, options, USAGE_FOOTER);
216    System.out.println(BackupRestoreConstants.VERIFY_BACKUP);
217  }
218
219  protected abstract String getUsageString();
220
221  private String getTablesForSet(Connection conn, String name) throws IOException {
222    try (final BackupSystemTable table = new BackupSystemTable(conn)) {
223      List<TableName> tables = table.describeBackupSet(name);
224
225      if (tables == null) {
226        return null;
227      }
228
229      return StringUtils.join(tables, BackupRestoreConstants.TABLENAME_DELIMITER_IN_COMMAND);
230    }
231  }
232}