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 System.out.println(info.getShortDescription());
294 }
295 }
296 }
297
298 private static class ProgressCommand extends Command {
299 CommandLine cmdline;
300
301 ProgressCommand(Configuration conf, CommandLine cmdline) {
302 super(conf);
303 this.cmdline = cmdline;
304 }
305
306 @Override
307 public void execute() throws IOException {
308 if (cmdline == null || cmdline.getArgs() == null ||
309 cmdline.getArgs().length != 2) {
310 System.out.println("No backup id was specified, "
311 + "will retrieve the most recent (ongoing) sessions");
312 }
313 String[] args = cmdline.getArgs();
314 if (args.length > 2) {
315 System.out.println("ERROR: wrong number of arguments: " + args.length);
316 System.out.println(PROGRESS_CMD_USAGE);
317 System.exit(-1);
318 }
319
320 String backupId = args == null ? null : args[1];
321 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
322 try(final Connection conn = ConnectionFactory.createConnection(conf);
323 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
324 int progress = admin.getProgress(backupId);
325 if(progress < 0){
326 System.out.println("No info was found for backup id: "+backupId);
327 } else{
328 System.out.println(backupId+" progress=" + progress+"%");
329 }
330 }
331 }
332 }
333
334 private static class DeleteCommand extends Command {
335
336 CommandLine cmdline;
337 DeleteCommand(Configuration conf, CommandLine cmdline) {
338 super(conf);
339 this.cmdline = cmdline;
340 }
341
342 @Override
343 public void execute() throws IOException {
344 if (cmdline == null || cmdline.getArgs() == null || cmdline.getArgs().length < 2) {
345 System.out.println("No backup id(s) was specified");
346 System.out.println(PROGRESS_CMD_USAGE);
347 System.exit(-1);
348 }
349 String[] args = cmdline.getArgs();
350
351 String[] backupIds = new String[args.length - 1];
352 System.arraycopy(args, 1, backupIds, 0, backupIds.length);
353 Configuration conf = getConf() != null ? getConf() : HBaseConfiguration.create();
354 try (final Connection conn = ConnectionFactory.createConnection(conf);
355 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();) {
356 int deleted = admin.deleteBackups(args);
357 System.out.println("Deleted " + deleted + " backups. Total requested: " + args.length);
358 }
359
360 }
361 }
362
363
364
365 private static class CancelCommand extends Command {
366 CommandLine cmdline;
367
368 CancelCommand(Configuration conf, CommandLine cmdline) {
369 super(conf);
370 this.cmdline = cmdline;
371 }
372
373 @Override
374 public void execute() throws IOException {
375 if (cmdline == null || cmdline.getArgs() == null || cmdline.getArgs().length < 2) {
376 System.out.println("No backup id(s) was specified, will use the most recent one");
377 }
378 String[] args = cmdline.getArgs();
379 String backupId = args == null || args.length == 0 ? null : args[1];
380 Configuration conf = getConf() != null ? getConf() : HBaseConfiguration.create();
381 try (final Connection conn = ConnectionFactory.createConnection(conf);
382 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();) {
383
384 }
385 }
386 }
387
388 private static class HistoryCommand extends Command {
389 CommandLine cmdline;
390 private final static int DEFAULT_HISTORY_LENGTH = 10;
391
392 HistoryCommand(Configuration conf, CommandLine cmdline) {
393 super(conf);
394 this.cmdline = cmdline;
395 }
396
397 @Override
398 public void execute() throws IOException {
399
400 int n = parseHistoryLength();
401 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
402 try(final Connection conn = ConnectionFactory.createConnection(conf);
403 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
404 List<BackupInfo> history = admin.getHistory(n);
405 for(BackupInfo info: history){
406 System.out.println(info.getShortDescription());
407 }
408 }
409 }
410
411 private int parseHistoryLength() {
412 String value = cmdline.getOptionValue("n");
413 if (value == null) return DEFAULT_HISTORY_LENGTH;
414 return Integer.parseInt(value);
415 }
416 }
417
418 private static class BackupSetCommand extends Command {
419 private final static String SET_ADD_CMD = "add";
420 private final static String SET_REMOVE_CMD = "remove";
421 private final static String SET_DELETE_CMD = "delete";
422 private final static String SET_DESCRIBE_CMD = "describe";
423 private final static String SET_LIST_CMD = "list";
424
425 CommandLine cmdline;
426
427 BackupSetCommand(Configuration conf, CommandLine cmdline) {
428 super(conf);
429 this.cmdline = cmdline;
430 }
431
432 @Override
433 public void execute() throws IOException {
434
435
436 if (cmdline == null || cmdline.getArgs() == null || cmdline.getArgs().length < 2) {
437 throw new IOException("command line format");
438 }
439 String[] args = cmdline.getArgs();
440 String cmdStr = args[1];
441 BackupCommand cmd = getCommand(cmdStr);
442
443 switch (cmd) {
444 case SET_ADD:
445 processSetAdd(args);
446 break;
447 case SET_REMOVE:
448 processSetRemove(args);
449 break;
450 case SET_DELETE:
451 processSetDelete(args);
452 break;
453 case SET_DESCRIBE:
454 processSetDescribe(args);
455 break;
456 case SET_LIST:
457 processSetList(args);
458 break;
459 default:
460 break;
461
462 }
463 }
464
465 private void processSetList(String[] args) throws IOException {
466
467
468 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
469 try(final Connection conn = ConnectionFactory.createConnection(conf);
470 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
471 List<BackupSet> list = admin.listBackupSets();
472 for(BackupSet bs: list){
473 System.out.println(bs);
474 }
475 }
476 }
477
478 private void processSetDescribe(String[] args) throws IOException {
479 if (args == null || args.length != 3) {
480 throw new RuntimeException("Wrong number of args: "+args.length);
481 }
482 String setName = args[2];
483 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
484 try(final Connection conn = ConnectionFactory.createConnection(conf);
485 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
486 BackupSet set = admin.getBackupSet(setName);
487 if(set == null) {
488 System.out.println("Set '"+setName+"' does not exist.");
489 } else{
490 System.out.println(set);
491 }
492 }
493 }
494
495 private void processSetDelete(String[] args) throws IOException {
496 if (args == null || args.length != 3) {
497 throw new RuntimeException("Wrong number of args");
498 }
499 String setName = args[2];
500 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
501 try(final Connection conn = ConnectionFactory.createConnection(conf);
502 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
503 boolean result = admin.deleteBackupSet(setName);
504 if(result){
505 System.out.println("Delete set "+setName+" OK.");
506 } else{
507 System.out.println("Set "+setName+" does not exist");
508 }
509 }
510 }
511
512 private void processSetRemove(String[] args) throws IOException {
513 if (args == null || args.length != 4) {
514 throw new RuntimeException("Wrong args");
515 }
516 String setName = args[2];
517 String[] tables = args[3].split(",");
518 Configuration conf = getConf() != null? getConf(): HBaseConfiguration.create();
519 try(final Connection conn = ConnectionFactory.createConnection(conf);
520 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
521 admin.removeFromBackupSet(setName, tables);
522 }
523 }
524
525 private void processSetAdd(String[] args) throws IOException {
526 if (args == null || args.length != 4) {
527 throw new RuntimeException("Wrong args");
528 }
529 String setName = args[2];
530 String[] tables = args[3].split(",");
531 TableName[] tableNames = new TableName[tables.length];
532 for(int i=0; i < tables.length; i++){
533 tableNames[i] = TableName.valueOf(tables[i]);
534 }
535 Configuration conf = getConf() != null? getConf():HBaseConfiguration.create();
536 try(final Connection conn = ConnectionFactory.createConnection(conf);
537 final BackupAdmin admin = conn.getAdmin().getBackupAdmin();){
538 admin.addToBackupSet(setName, tableNames);
539 }
540
541 }
542
543 private BackupCommand getCommand(String cmdStr) throws IOException {
544 if (cmdStr.equals(SET_ADD_CMD)) {
545 return BackupCommand.SET_ADD;
546 } else if (cmdStr.equals(SET_REMOVE_CMD)) {
547 return BackupCommand.SET_REMOVE;
548 } else if (cmdStr.equals(SET_DELETE_CMD)) {
549 return BackupCommand.SET_DELETE;
550 } else if (cmdStr.equals(SET_DESCRIBE_CMD)) {
551 return BackupCommand.SET_DESCRIBE;
552 } else if (cmdStr.equals(SET_LIST_CMD)) {
553 return BackupCommand.SET_LIST;
554 } else {
555 throw new IOException("Unknown command for 'set' :" + cmdStr);
556 }
557 }
558
559 }
560 }