1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.backup.impl;
20
21 import java.io.IOException;
22 import java.util.List;
23
24 import org.apache.commons.cli.CommandLine;
25 import org.apache.commons.lang.StringUtils;
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.conf.Configured;
28 import org.apache.hadoop.hbase.HBaseConfiguration;
29 import org.apache.hadoop.hbase.TableName;
30 import org.apache.hadoop.hbase.backup.BackupInfo;
31 import org.apache.hadoop.hbase.backup.BackupRequest;
32 import org.apache.hadoop.hbase.backup.BackupType;
33 import org.apache.hadoop.hbase.backup.impl.BackupRestoreConstants.BackupCommand;
34 import org.apache.hadoop.hbase.backup.util.BackupClientUtil;
35 import org.apache.hadoop.hbase.backup.util.BackupSet;
36 import org.apache.hadoop.hbase.classification.InterfaceAudience;
37 import org.apache.hadoop.hbase.classification.InterfaceStability;
38 import org.apache.hadoop.hbase.client.Admin;
39 import org.apache.hadoop.hbase.client.BackupAdmin;
40 import org.apache.hadoop.hbase.client.Connection;
41 import org.apache.hadoop.hbase.client.ConnectionFactory;
42
43 import com.google.common.collect.Lists;
44
45
46
47
48 @InterfaceAudience.Private
49 @InterfaceStability.Evolving
50 public final class BackupCommands {
51
52 private static final String USAGE = "Usage: hbase backup COMMAND\n"
53 + "where COMMAND is one of:\n"
54 + " create create a new backup image\n"
55 + " cancel cancel an ongoing backup\n"
56 + " delete delete an existing backup image\n"
57 + " describe show the detailed information of a backup image\n"
58 + " history show history of all successful backups\n"
59 + " progress show the progress of the latest backup request\n"
60 + " set backup set management\n"
61 + "Enter \'help COMMAND\' to see help message for each command\n";
62
63 private static final String CREATE_CMD_USAGE =
64 "Usage: hbase backup create <type> <backup_root_path> [tables] [-s name] [-convert] "
65 + "[-silent] [-w workers][-b bandwith]\n" + " type \"full\" to create a full backup image;\n"
66 + " \"incremental\" to create an incremental backup image\n"
67 + " backup_root_path The full root path to store the backup image,\n"
68 + " the prefix can be hdfs, webhdfs or gpfs\n" + " Options:\n"
69 + " tables If no tables (\"\") are specified, all tables are backed up. "
70 + "Otherwise it is a\n" + " comma separated list of tables.\n"
71 + " -w number of parallel workers.\n"
72 + " -b bandwith per one worker (in MB sec)\n"
73 + " -set name of backup set" ;
74
75 private static final String PROGRESS_CMD_USAGE = "Usage: hbase backup progress <backupId>\n"
76 + " backupId backup image id;\n";
77
78 private static final String DESCRIBE_CMD_USAGE = "Usage: hbase backup decsribe <backupId>\n"
79 + " backupId backup image id\n";
80
81 private static final String HISTORY_CMD_USAGE = "Usage: hbase backup history [-n N]\n"
82 + " -n N show up to N last backup sessions, default - 10;\n";
83
84 private static final String DELETE_CMD_USAGE = "Usage: hbase backup delete <backupId>\n"
85 + " backupId backup image id;\n";
86
87 private static final String CANCEL_CMD_USAGE = "Usage: hbase backup cancel <backupId>\n"
88 + " backupId backup image id;\n";
89
90 private static final String SET_CMD_USAGE = "Usage: hbase backup set COMMAND [name] [tables]\n"
91 + " name Backup set name\n"
92 + " tables If no tables (\"\") are specified, all tables will belong to the set. "
93 + "Otherwise it is a\n" + " comma separated list of tables.\n"
94 + "where COMMAND is one of:\n"
95 + " add add tables to a set, crete set if needed\n"
96 + " remove remove tables from set\n"
97 + " list list all sets\n"
98 + " describe describes set\n"
99 + " delete delete backup set\n";
100
101 public static abstract class Command extends Configured {
102 Command(Configuration conf) {
103 super(conf);
104 }
105 public abstract void execute() throws IOException;
106 }
107
108 private BackupCommands() {
109 throw new AssertionError("Instantiating utility class...");
110 }
111
112 public static Command createCommand(Configuration conf, BackupCommand type, CommandLine cmdline) {
113 Command cmd = null;
114 switch (type) {
115 case CREATE:
116 cmd = new CreateCommand(conf, cmdline);
117 break;
118 case DESCRIBE:
119 cmd = new DescribeCommand(conf, cmdline);
120 break;
121 case PROGRESS:
122 cmd = new ProgressCommand(conf, cmdline);
123 break;
124 case DELETE:
125 cmd = new DeleteCommand(conf, cmdline);
126 break;
127 case CANCEL:
128 cmd = new CancelCommand(conf, cmdline);
129 break;
130 case HISTORY:
131 cmd = new HistoryCommand(conf, cmdline);
132 break;
133 case SET:
134 cmd = new BackupSetCommand(conf, cmdline);
135 break;
136 case HELP:
137 default:
138 cmd = new HelpCommand(conf, cmdline);
139 break;
140 }
141 return cmd;
142 }
143
144
145 public static class CreateCommand extends Command {
146 CommandLine cmdline;
147
148 CreateCommand(Configuration conf, CommandLine cmdline) {
149 super(conf);
150 this.cmdline = cmdline;
151 }
152
153 @Override
154 public void execute() throws IOException {
155 if (cmdline == null || cmdline.getArgs() == null) {
156 System.out.println("ERROR: missing arguments");
157 System.out.println(CREATE_CMD_USAGE);
158 System.exit(-1);
159 }
160 String[] args = cmdline.getArgs();
161 if (args.length < 3 || args.length > 4) {
162 System.out.println("ERROR: wrong number of arguments");
163 System.out.println(CREATE_CMD_USAGE);
164 System.exit(-1);
165 }
166
167 if (!BackupType.FULL.toString().equalsIgnoreCase(args[1])
168 && !BackupType.INCREMENTAL.toString().equalsIgnoreCase(args[1])) {
169 System.out.println("ERROR: invalid backup type");
170 System.out.println(CREATE_CMD_USAGE);
171 System.exit(-1);
172 }
173
174 String tables = null;
175 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
176
177
178 if (cmdline.hasOption("set")) {
179 String setName = cmdline.getOptionValue("set");
180 tables = getTablesForSet(setName, conf);
181
182 if (tables == null) throw new IOException("Backup set '" + setName
183 + "' is either empty or does not exist");
184 } else {
185 tables = (args.length == 4) ? args[3] : null;
186 }
187 int bandwidth = cmdline.hasOption('b') ? Integer.parseInt(cmdline.getOptionValue('b')) : -1;
188 int workers = cmdline.hasOption('w') ? Integer.parseInt(cmdline.getOptionValue('w')) : -1;
189
190 try (Connection conn = ConnectionFactory.createConnection(getConf());
191 Admin admin = conn.getAdmin();
192 BackupAdmin backupAdmin = admin.getBackupAdmin();) {
193 BackupRequest request = new BackupRequest();
194 request.setBackupType(BackupType.valueOf(args[1].toUpperCase()))
195 .setTableList(tables != null?Lists.newArrayList(BackupClientUtil.parseTableNames(tables)): null)
196 .setTargetRootDir(args[2]).setWorkers(workers).setBandwidth(bandwidth);
197 String backupId = backupAdmin.backupTables(request);
198 System.out.println("Backup session "+ backupId+" finished. Status: SUCCESS");
199 } catch (IOException e) {
200 System.out.println("Backup session finished. Status: FAILURE");
201 throw e;
202 }
203 }
204 private String getTablesForSet(String name, Configuration conf)
205 throws IOException {
206 try (final Connection conn = ConnectionFactory.createConnection(conf);
207 final BackupSystemTable table = new BackupSystemTable(conn)) {
208 List<TableName> tables = table.describeBackupSet(name);
209 if (tables == null) return null;
210 return StringUtils.join(tables, BackupRestoreConstants.TABLENAME_DELIMITER_IN_COMMAND);
211 }
212 }
213 }
214
215 private static class HelpCommand extends Command {
216 CommandLine cmdline;
217
218 HelpCommand(Configuration conf, CommandLine cmdline) {
219 super(conf);
220 this.cmdline = cmdline;
221 }
222
223 @Override
224 public void execute() throws IOException {
225 if (cmdline == null) {
226 System.out.println(USAGE);
227 System.exit(0);
228 }
229
230 String[] args = cmdline.getArgs();
231 if (args == null || args.length == 0) {
232 System.out.println(USAGE);
233 System.exit(0);
234 }
235
236 if (args.length != 2) {
237 System.out.println("Only support check help message of a single command type");
238 System.out.println(USAGE);
239 System.exit(0);
240 }
241
242 String type = args[1];
243
244 if (BackupCommand.CREATE.name().equalsIgnoreCase(type)) {
245 System.out.println(CREATE_CMD_USAGE);
246 } else if (BackupCommand.DESCRIBE.name().equalsIgnoreCase(type)) {
247 System.out.println(DESCRIBE_CMD_USAGE);
248 } else if (BackupCommand.HISTORY.name().equalsIgnoreCase(type)) {
249 System.out.println(HISTORY_CMD_USAGE);
250 } else if (BackupCommand.PROGRESS.name().equalsIgnoreCase(type)) {
251 System.out.println(PROGRESS_CMD_USAGE);
252 } else if (BackupCommand.DELETE.name().equalsIgnoreCase(type)) {
253 System.out.println(DELETE_CMD_USAGE);
254 } else if (BackupCommand.CANCEL.name().equalsIgnoreCase(type)) {
255 System.out.println(CANCEL_CMD_USAGE);
256 } else if (BackupCommand.SET.name().equalsIgnoreCase(type)) {
257 System.out.println(SET_CMD_USAGE);
258 } else {
259 System.out.println("Unknown command : " + type);
260 System.out.println(USAGE);
261 }
262 System.exit(0);
263 }
264 }
265
266 private static class DescribeCommand extends Command {
267 CommandLine cmdline;
268
269 DescribeCommand(Configuration conf, CommandLine cmdline) {
270 super(conf);
271 this.cmdline = cmdline;
272 }
273
274 @Override
275 public void execute() throws IOException {
276 if (cmdline == null || cmdline.getArgs() == null) {
277 System.out.println("ERROR: missing arguments");
278 System.out.println(DESCRIBE_CMD_USAGE);
279 System.exit(-1);
280 }
281 String[] args = cmdline.getArgs();
282 if (args.length != 2) {
283 System.out.println("ERROR: wrong number of arguments");
284 System.out.println(DESCRIBE_CMD_USAGE);
285 System.exit(-1);
286 }
287
288 String backupId = args[1];
289 Configuration conf = getConf() != null ? getConf() : HBaseConfiguration.create();
290 try (final Connection conn = ConnectionFactory.createConnection(conf);
291 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();) {
292 BackupInfo info = admin.getBackupInfo(backupId);
293 if (info != null) {
294 System.out.println(info.getShortDescription());
295 } else {
296 System.out.println("ERROR: "+ backupId +" not found");
297 }
298 }
299 }
300 }
301
302 private static class ProgressCommand extends Command {
303 CommandLine cmdline;
304
305 ProgressCommand(Configuration conf, CommandLine cmdline) {
306 super(conf);
307 this.cmdline = cmdline;
308 }
309
310 @Override
311 public void execute() throws IOException {
312 if (cmdline == null || cmdline.getArgs() == null ||
313 cmdline.getArgs().length != 2) {
314 System.out.println("No backup id was specified, "
315 + "will retrieve the most recent (ongoing) sessions");
316 }
317 String[] args = cmdline.getArgs();
318 if (args.length > 2) {
319 System.out.println("ERROR: wrong number of arguments: " + args.length);
320 System.out.println(PROGRESS_CMD_USAGE);
321 System.exit(-1);
322 }
323
324 String backupId = (args == null || args.length <= 1) ? null : args[1];
325 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
326 try(final Connection conn = ConnectionFactory.createConnection(conf);
327 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
328 int progress = admin.getProgress(backupId);
329 if(progress < 0){
330 System.out.println("No info was found for backup id: "+backupId);
331 } else{
332 System.out.println(backupId+" progress=" + progress+"%");
333 }
334 }
335 }
336 }
337
338 private static class DeleteCommand extends Command {
339
340 CommandLine cmdline;
341 DeleteCommand(Configuration conf, CommandLine cmdline) {
342 super(conf);
343 this.cmdline = cmdline;
344 }
345
346 @Override
347 public void execute() throws IOException {
348 if (cmdline == null || cmdline.getArgs() == null || cmdline.getArgs().length < 2) {
349 System.out.println("No backup id(s) was specified");
350 System.out.println(PROGRESS_CMD_USAGE);
351 System.exit(-1);
352 }
353 String[] args = cmdline.getArgs();
354
355 String[] backupIds = new String[args.length - 1];
356 System.arraycopy(args, 1, backupIds, 0, backupIds.length);
357 Configuration conf = getConf() != null ? getConf() : HBaseConfiguration.create();
358 try (final Connection conn = ConnectionFactory.createConnection(conf);
359 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();) {
360 int deleted = admin.deleteBackups(args);
361 System.out.println("Deleted " + deleted + " backups. Total requested: " + args.length);
362 }
363
364 }
365 }
366
367
368
369 private static class CancelCommand extends Command {
370 CommandLine cmdline;
371
372 CancelCommand(Configuration conf, CommandLine cmdline) {
373 super(conf);
374 this.cmdline = cmdline;
375 }
376
377 @Override
378 public void execute() throws IOException {
379 if (cmdline == null || cmdline.getArgs() == null || cmdline.getArgs().length < 2) {
380 System.out.println("No backup id(s) was specified, will use the most recent one");
381 }
382 String[] args = cmdline.getArgs();
383 String backupId = args == null || args.length == 0 ? null : args[1];
384 Configuration conf = getConf() != null ? getConf() : HBaseConfiguration.create();
385 try (final Connection conn = ConnectionFactory.createConnection(conf);
386 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();) {
387
388 }
389 }
390 }
391
392 private static class HistoryCommand extends Command {
393 CommandLine cmdline;
394 private final static int DEFAULT_HISTORY_LENGTH = 10;
395
396 HistoryCommand(Configuration conf, CommandLine cmdline) {
397 super(conf);
398 this.cmdline = cmdline;
399 }
400
401 @Override
402 public void execute() throws IOException {
403
404 int n = parseHistoryLength();
405 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
406 try(final Connection conn = ConnectionFactory.createConnection(conf);
407 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
408 List<BackupInfo> history = admin.getHistory(n);
409 for(BackupInfo info: history){
410 System.out.println(info.getShortDescription());
411 }
412 }
413 }
414
415 private int parseHistoryLength() {
416 String value = cmdline.getOptionValue("n");
417 if (value == null) return DEFAULT_HISTORY_LENGTH;
418 return Integer.parseInt(value);
419 }
420 }
421
422 private static class BackupSetCommand extends Command {
423 private final static String SET_ADD_CMD = "add";
424 private final static String SET_REMOVE_CMD = "remove";
425 private final static String SET_DELETE_CMD = "delete";
426 private final static String SET_DESCRIBE_CMD = "describe";
427 private final static String SET_LIST_CMD = "list";
428
429 CommandLine cmdline;
430
431 BackupSetCommand(Configuration conf, CommandLine cmdline) {
432 super(conf);
433 this.cmdline = cmdline;
434 }
435
436 @Override
437 public void execute() throws IOException {
438
439
440 if (cmdline == null || cmdline.getArgs() == null || cmdline.getArgs().length < 2) {
441 throw new IOException("command line format");
442 }
443 String[] args = cmdline.getArgs();
444 String cmdStr = args[1];
445 BackupCommand cmd = getCommand(cmdStr);
446
447 switch (cmd) {
448 case SET_ADD:
449 processSetAdd(args);
450 break;
451 case SET_REMOVE:
452 processSetRemove(args);
453 break;
454 case SET_DELETE:
455 processSetDelete(args);
456 break;
457 case SET_DESCRIBE:
458 processSetDescribe(args);
459 break;
460 case SET_LIST:
461 processSetList(args);
462 break;
463 default:
464 break;
465
466 }
467 }
468
469 private void processSetList(String[] args) throws IOException {
470
471
472 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
473 try(final Connection conn = ConnectionFactory.createConnection(conf);
474 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
475 List<BackupSet> list = admin.listBackupSets();
476 for(BackupSet bs: list){
477 System.out.println(bs);
478 }
479 }
480 }
481
482 private void processSetDescribe(String[] args) throws IOException {
483 if (args == null || args.length != 3) {
484 throw new RuntimeException("Wrong number of args: "+args.length);
485 }
486 String setName = args[2];
487 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
488 try(final Connection conn = ConnectionFactory.createConnection(conf);
489 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
490 BackupSet set = admin.getBackupSet(setName);
491 if(set == null) {
492 System.out.println("Set '"+setName+"' does not exist.");
493 } else{
494 System.out.println(set);
495 }
496 }
497 }
498
499 private void processSetDelete(String[] args) throws IOException {
500 if (args == null || args.length != 3) {
501 throw new RuntimeException("Wrong number of args");
502 }
503 String setName = args[2];
504 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
505 try(final Connection conn = ConnectionFactory.createConnection(conf);
506 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
507 boolean result = admin.deleteBackupSet(setName);
508 if(result){
509 System.out.println("Delete set "+setName+" OK.");
510 } else{
511 System.out.println("Set "+setName+" does not exist");
512 }
513 }
514 }
515
516 private void processSetRemove(String[] args) throws IOException {
517 if (args == null || args.length != 4) {
518 throw new RuntimeException("Wrong args");
519 }
520 String setName = args[2];
521 String[] tables = args[3].split(",");
522 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
523 try(final Connection conn = ConnectionFactory.createConnection(conf);
524 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
525 admin.removeFromBackupSet(setName, tables);
526 }
527 }
528
529 private void processSetAdd(String[] args) throws IOException {
530 if (args == null || args.length != 4) {
531 throw new RuntimeException("Wrong args");
532 }
533 String setName = args[2];
534 String[] tables = args[3].split(",");
535 TableName[] tableNames = new TableName[tables.length];
536 for(int i=0; i < tables.length; i++){
537 tableNames[i] = TableName.valueOf(tables[i]);
538 }
539 Configuration conf = getConf() != null? getConf():HBaseConfiguration.create();
540 try(final Connection conn = ConnectionFactory.createConnection(conf);
541 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
542 admin.addToBackupSet(setName, tableNames);
543 }
544
545 }
546
547 private BackupCommand getCommand(String cmdStr) throws IOException {
548 if (cmdStr.equals(SET_ADD_CMD)) {
549 return BackupCommand.SET_ADD;
550 } else if (cmdStr.equals(SET_REMOVE_CMD)) {
551 return BackupCommand.SET_REMOVE;
552 } else if (cmdStr.equals(SET_DELETE_CMD)) {
553 return BackupCommand.SET_DELETE;
554 } else if (cmdStr.equals(SET_DESCRIBE_CMD)) {
555 return BackupCommand.SET_DESCRIBE;
556 } else if (cmdStr.equals(SET_LIST_CMD)) {
557 return BackupCommand.SET_LIST;
558 } else {
559 throw new IOException("Unknown command for 'set' :" + cmdStr);
560 }
561 }
562
563 }
564 }