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.junit.jupiter.api.Assertions.assertFalse;
021import static org.junit.jupiter.api.Assertions.assertThrows;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.io.IOException;
025import java.util.List;
026import org.apache.commons.lang3.StringUtils;
027import org.apache.hadoop.hbase.TableName;
028import org.apache.hadoop.hbase.backup.util.BackupUtils;
029import org.apache.hadoop.hbase.client.Admin;
030import org.apache.hadoop.hbase.client.Table;
031import org.apache.hadoop.hbase.testclassification.LargeTests;
032import org.apache.hadoop.util.ToolRunner;
033import org.junit.jupiter.api.Tag;
034import org.junit.jupiter.api.Test;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
039
040@Tag(LargeTests.TAG)
041public class TestFullRestore extends TestBackupBase {
042
043  private static final Logger LOG = LoggerFactory.getLogger(TestFullRestore.class);
044
045  /**
046   * Verify that a single table is restored to a new table.
047   * @throws Exception if doing the backup, restoring it or an operation on the tables fails
048   */
049  @Test
050  public void testFullRestoreSingle() throws Exception {
051    LOG.info("test full restore on a single table empty table");
052
053    List<TableName> tables = Lists.newArrayList(table1);
054    String backupId = fullTableBackup(tables);
055    assertTrue(checkSucceeded(backupId));
056
057    LOG.info("backup complete");
058
059    TableName[] tableset = new TableName[] { table1 };
060    TableName[] tablemap = new TableName[] { table1_restore };
061    BackupAdmin client = getBackupAdmin();
062    client.restore(BackupUtils.createRestoreRequest(BACKUP_ROOT_DIR, backupId, false, tableset,
063      tablemap, false));
064    Admin hba = TEST_UTIL.getAdmin();
065    assertTrue(hba.tableExists(table1_restore));
066    TEST_UTIL.deleteTable(table1_restore);
067    hba.close();
068  }
069
070  @Test
071  public void testFullRestoreSingleWithRegion() throws Exception {
072    LOG.info("test full restore on a single table empty table that has a region");
073
074    // This test creates its own table so other tests are not affected (we adjust it in this test)
075    TableName tableName = TableName.valueOf("table-full-restore-single-region");
076    TEST_UTIL.createTable(tableName, famName);
077
078    Admin admin = TEST_UTIL.getAdmin();
079
080    // Add & remove data to ensure a region is active, but functionally empty
081    Table table = TEST_UTIL.getConnection().getTable(tableName);
082    loadTable(table);
083    admin.flush(tableName);
084    TEST_UTIL.deleteTableData(tableName);
085    admin.flush(tableName);
086
087    TEST_UTIL.compact(tableName, true);
088
089    List<TableName> tables = Lists.newArrayList(tableName);
090    String backupId = fullTableBackup(tables);
091    assertTrue(checkSucceeded(backupId));
092
093    LOG.info("backup complete");
094
095    TEST_UTIL.deleteTable(tableName);
096
097    TableName[] tableset = new TableName[] { tableName };
098    TableName[] tablemap = new TableName[] { tableName };
099    BackupAdmin client = getBackupAdmin();
100    client.restore(BackupUtils.createRestoreRequest(BACKUP_ROOT_DIR, backupId, false, tableset,
101      tablemap, false));
102    assertTrue(admin.tableExists(tableName));
103    TEST_UTIL.deleteTable(tableName);
104    admin.close();
105  }
106
107  @Test
108  public void testFullRestoreSingleCommand() throws Exception {
109    LOG.info("test full restore on a single table empty table: command-line");
110
111    List<TableName> tables = Lists.newArrayList(table1);
112    String backupId = fullTableBackup(tables);
113    LOG.info("backup complete");
114    assertTrue(checkSucceeded(backupId));
115    // restore <backup_root_path> <backup_id> <tables> [tableMapping]
116    String[] args = new String[] { BACKUP_ROOT_DIR, backupId, "-t", table1.getNameAsString(), "-m",
117      table1_restore.getNameAsString() };
118    // Run backup
119    int ret = ToolRunner.run(conf1, new RestoreDriver(), args);
120
121    assertTrue(ret == 0);
122    Admin hba = TEST_UTIL.getAdmin();
123    assertTrue(hba.tableExists(table1_restore));
124    TEST_UTIL.deleteTable(table1_restore);
125    hba.close();
126  }
127
128  @Test
129  public void testFullRestoreCheckCommand() throws Exception {
130    LOG.info("test full restore on a single table: command-line, check only");
131
132    List<TableName> tables = Lists.newArrayList(table1);
133    String backupId = fullTableBackup(tables);
134    LOG.info("backup complete");
135    assertTrue(checkSucceeded(backupId));
136    // restore <backup_root_path> <backup_id> <tables> [tableMapping]
137    String[] args = new String[] { BACKUP_ROOT_DIR, backupId, "-t", table1.getNameAsString(), "-m",
138      table1_restore.getNameAsString(), "-c" };
139    // Run backup
140    int ret = ToolRunner.run(conf1, new RestoreDriver(), args);
141    assertTrue(ret == 0);
142    // Verify that table has not been restored
143    Admin hba = TEST_UTIL.getAdmin();
144    assertFalse(hba.tableExists(table1_restore));
145  }
146
147  /**
148   * Verify that multiple tables are restored to new tables.
149   * @throws Exception if doing the backup, restoring it or an operation on the tables fails
150   */
151  @Test
152  public void testFullRestoreMultiple() throws Exception {
153    LOG.info("create full backup image on multiple tables");
154    List<TableName> tables = Lists.newArrayList(table2, table3);
155    String backupId = fullTableBackup(tables);
156    assertTrue(checkSucceeded(backupId));
157
158    TableName[] restore_tableset = new TableName[] { table2, table3 };
159    TableName[] tablemap = new TableName[] { table2_restore, table3_restore };
160    BackupAdmin client = getBackupAdmin();
161    client.restore(BackupUtils.createRestoreRequest(BACKUP_ROOT_DIR, backupId, false,
162      restore_tableset, tablemap, false));
163    Admin hba = TEST_UTIL.getAdmin();
164    assertTrue(hba.tableExists(table2_restore));
165    assertTrue(hba.tableExists(table3_restore));
166    TEST_UTIL.deleteTable(table2_restore);
167    TEST_UTIL.deleteTable(table3_restore);
168    hba.close();
169  }
170
171  /**
172   * Verify that multiple tables are restored to new tables.
173   * @throws Exception if doing the backup, restoring it or an operation on the tables fails
174   */
175  @Test
176  public void testFullRestoreMultipleCommand() throws Exception {
177    LOG.info("create full backup image on multiple tables: command-line");
178    List<TableName> tables = Lists.newArrayList(table2, table3);
179    String backupId = fullTableBackup(tables);
180    assertTrue(checkSucceeded(backupId));
181
182    TableName[] restore_tableset = new TableName[] { table2, table3 };
183    TableName[] tablemap = new TableName[] { table2_restore, table3_restore };
184
185    // restore <backup_root_path> <backup_id> <tables> [tableMapping]
186    String[] args = new String[] { BACKUP_ROOT_DIR, backupId, "-t",
187      StringUtils.join(restore_tableset, ","), "-m", StringUtils.join(tablemap, ",") };
188    // Run backup
189    int ret = ToolRunner.run(conf1, new RestoreDriver(), args);
190
191    assertTrue(ret == 0);
192    Admin hba = TEST_UTIL.getAdmin();
193    assertTrue(hba.tableExists(table2_restore));
194    assertTrue(hba.tableExists(table3_restore));
195    TEST_UTIL.deleteTable(table2_restore);
196    TEST_UTIL.deleteTable(table3_restore);
197    hba.close();
198  }
199
200  /**
201   * Verify that a single table is restored using overwrite.
202   * @throws Exception if doing the backup or restoring it fails
203   */
204  @Test
205  public void testFullRestoreSingleOverwrite() throws Exception {
206    LOG.info("test full restore on a single table empty table");
207    List<TableName> tables = Lists.newArrayList(table1);
208    String backupId = fullTableBackup(tables);
209    assertTrue(checkSucceeded(backupId));
210
211    LOG.info("backup complete");
212
213    TableName[] tableset = new TableName[] { table1 };
214    BackupAdmin client = getBackupAdmin();
215    client.restore(
216      BackupUtils.createRestoreRequest(BACKUP_ROOT_DIR, backupId, false, tableset, null, true));
217  }
218
219  /**
220   * Verify that a single table is restored using overwrite.
221   * @throws Exception if doing the backup or an operation on the tables fails
222   */
223  @Test
224  public void testFullRestoreSingleOverwriteCommand() throws Exception {
225    LOG.info("test full restore on a single table empty table: command-line");
226    List<TableName> tables = Lists.newArrayList(table1);
227    String backupId = fullTableBackup(tables);
228    assertTrue(checkSucceeded(backupId));
229    LOG.info("backup complete");
230    TableName[] tableset = new TableName[] { table1 };
231    // restore <backup_root_path> <backup_id> <tables> [tableMapping]
232    String[] args =
233      new String[] { BACKUP_ROOT_DIR, backupId, "-t", StringUtils.join(tableset, ","), "-o" };
234    // Run restore
235    int ret = ToolRunner.run(conf1, new RestoreDriver(), args);
236    assertTrue(ret == 0);
237
238    Admin hba = TEST_UTIL.getAdmin();
239    assertTrue(hba.tableExists(table1));
240    hba.close();
241  }
242
243  /**
244   * Verify that multiple tables are restored to new tables using overwrite.
245   * @throws Exception if doing the backup or restoring it fails
246   */
247  @Test
248  public void testFullRestoreMultipleOverwrite() throws Exception {
249    LOG.info("create full backup image on multiple tables");
250
251    List<TableName> tables = Lists.newArrayList(table2, table3);
252    String backupId = fullTableBackup(tables);
253    assertTrue(checkSucceeded(backupId));
254
255    TableName[] restore_tableset = new TableName[] { table2, table3 };
256    BackupAdmin client = getBackupAdmin();
257    client.restore(BackupUtils.createRestoreRequest(BACKUP_ROOT_DIR, backupId, false,
258      restore_tableset, null, true));
259  }
260
261  /**
262   * Verify that multiple tables are restored to new tables using overwrite.
263   * @throws Exception if doing the backup or an operation on the tables fails
264   */
265  @Test
266  public void testFullRestoreMultipleOverwriteCommand() throws Exception {
267    LOG.info("create full backup image on multiple tables: command-line");
268
269    List<TableName> tables = Lists.newArrayList(table2, table3);
270    String backupId = fullTableBackup(tables);
271    assertTrue(checkSucceeded(backupId));
272
273    TableName[] restore_tableset = new TableName[] { table2, table3 };
274    // restore <backup_root_path> <backup_id> <tables> [tableMapping]
275    String[] args = new String[] { BACKUP_ROOT_DIR, backupId, "-t",
276      StringUtils.join(restore_tableset, ","), "-o" };
277    // Run backup
278    int ret = ToolRunner.run(conf1, new RestoreDriver(), args);
279
280    assertTrue(ret == 0);
281    Admin hba = TEST_UTIL.getAdmin();
282    assertTrue(hba.tableExists(table2));
283    assertTrue(hba.tableExists(table3));
284    hba.close();
285  }
286
287  /**
288   * Verify that restore fails on a single table that does not exist.
289   * @throws Exception if doing the backup or restoring it fails
290   */
291  @Test
292  public void testFullRestoreSingleDNE() throws Exception {
293    assertThrows(IOException.class, () -> {
294      LOG.info("test restore fails on a single table that does not exist");
295      List<TableName> tables = Lists.newArrayList(table1);
296      String backupId = fullTableBackup(tables);
297      assertTrue(checkSucceeded(backupId));
298
299      LOG.info("backup complete");
300
301      TableName[] tableset = new TableName[] { TableName.valueOf("faketable") };
302      TableName[] tablemap = new TableName[] { table1_restore };
303      BackupAdmin client = getBackupAdmin();
304      client.restore(BackupUtils.createRestoreRequest(BACKUP_ROOT_DIR, backupId, false, tableset,
305        tablemap, false));
306    });
307  }
308
309  /**
310   * Verify that restore fails on a single table that does not exist.
311   * @throws Exception if doing the backup or restoring it fails
312   */
313  @Test
314  public void testFullRestoreSingleDNECommand() throws Exception {
315    LOG.info("test restore fails on a single table that does not exist: command-line");
316    List<TableName> tables = Lists.newArrayList(table1);
317    String backupId = fullTableBackup(tables);
318    assertTrue(checkSucceeded(backupId));
319
320    LOG.info("backup complete");
321
322    TableName[] tableset = new TableName[] { TableName.valueOf("faketable") };
323    TableName[] tablemap = new TableName[] { table1_restore };
324    String[] args = new String[] { BACKUP_ROOT_DIR, backupId, StringUtils.join(tableset, ","), "-m",
325      StringUtils.join(tablemap, ",") };
326    // Run restore
327    int ret = ToolRunner.run(conf1, new RestoreDriver(), args);
328    assertTrue(ret != 0);
329  }
330
331  /**
332   * Verify that restore fails on multiple tables that do not exist.
333   * @throws Exception if doing the backup or restoring it fails
334   */
335  @Test
336  public void testFullRestoreMultipleDNE() throws Exception {
337    assertThrows(IOException.class, () -> {
338      LOG.info("test restore fails on multiple tables that do not exist");
339
340      List<TableName> tables = Lists.newArrayList(table2, table3);
341      String backupId = fullTableBackup(tables);
342      assertTrue(checkSucceeded(backupId));
343
344      TableName[] restore_tableset =
345        new TableName[] { TableName.valueOf("faketable1"), TableName.valueOf("faketable2") };
346      TableName[] tablemap = new TableName[] { table2_restore, table3_restore };
347      BackupAdmin client = getBackupAdmin();
348      client.restore(BackupUtils.createRestoreRequest(BACKUP_ROOT_DIR, backupId, false,
349        restore_tableset, tablemap, false));
350    });
351  }
352
353  /**
354   * Verify that restore fails on multiple tables that do not exist.
355   * @throws Exception if doing the backup or restoring it fails
356   */
357  @Test
358  public void testFullRestoreMultipleDNECommand() throws Exception {
359    LOG.info("test restore fails on multiple tables that do not exist: command-line");
360
361    List<TableName> tables = Lists.newArrayList(table2, table3);
362    String backupId = fullTableBackup(tables);
363    assertTrue(checkSucceeded(backupId));
364
365    TableName[] restore_tableset =
366      new TableName[] { TableName.valueOf("faketable1"), TableName.valueOf("faketable2") };
367    TableName[] tablemap = new TableName[] { table2_restore, table3_restore };
368    String[] args = new String[] { BACKUP_ROOT_DIR, backupId,
369      StringUtils.join(restore_tableset, ","), "-m", StringUtils.join(tablemap, ",") };
370    // Run restore
371    int ret = ToolRunner.run(conf1, new RestoreDriver(), args);
372    assertTrue(ret != 0);
373  }
374}