001/* 002 * Copyright 2008-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2008-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds.tasks; 037 038 039 040import java.util.ArrayList; 041import java.util.Arrays; 042import java.util.Collections; 043import java.util.Date; 044import java.util.LinkedHashMap; 045import java.util.List; 046import java.util.Map; 047 048import com.unboundid.ldap.sdk.Attribute; 049import com.unboundid.ldap.sdk.Entry; 050import com.unboundid.util.NotMutable; 051import com.unboundid.util.NotNull; 052import com.unboundid.util.Nullable; 053import com.unboundid.util.StaticUtils; 054import com.unboundid.util.ThreadSafety; 055import com.unboundid.util.ThreadSafetyLevel; 056import com.unboundid.util.Validator; 057 058import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 059 060 061 062/** 063 * This class defines a Directory Server task that can be used to restore a 064 * backup. 065 * <BR> 066 * <BLOCKQUOTE> 067 * <B>NOTE:</B> This class, and other classes within the 068 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 069 * supported for use against Ping Identity, UnboundID, and 070 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 071 * for proprietary functionality or for external specifications that are not 072 * considered stable or mature enough to be guaranteed to work in an 073 * interoperable way with other types of LDAP servers. 074 * </BLOCKQUOTE> 075 * <BR> 076 * The properties that are available for use with this type of task include: 077 * <UL> 078 * <LI>The path to the backup directory in which the backup resides. This 079 * must be provided when scheduling a new task of this type.</LI> 080 * <LI>The backup ID of the backup to be restored. If this is not provided 081 * when scheduling an instance of this task, then the most recent backup 082 * in the backup directory will be selected.</LI> 083 * <LI>A flag that indicates whether to attempt to restore the backup or 084 * only to verify it to determine whether it appears to be valid (e.g., 085 * validate the digest and/or signature, make sure that the backend 086 * considers it valid, etc.).</LI> 087 * <LI>The path to a file containing a passphrase to use to generate the 088 * encryption key.</LI> 089 * </UL> 090 091 */ 092@NotMutable() 093@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 094public final class RestoreTask 095 extends Task 096{ 097 /** 098 * The fully-qualified name of the Java class that is used for the restore 099 * task. 100 */ 101 @NotNull static final String RESTORE_TASK_CLASS = 102 "com.unboundid.directory.server.tasks.RestoreTask"; 103 104 105 106 /** 107 * The name of the attribute used to specify the path to the backup directory 108 * containing the backup to restore. 109 */ 110 @NotNull private static final String ATTR_BACKUP_DIRECTORY = 111 "ds-backup-directory-path"; 112 113 114 115 /** 116 * The name of the attribute used to specify the backup ID of the backup to 117 * restore. 118 */ 119 @NotNull private static final String ATTR_BACKUP_ID = "ds-backup-id"; 120 121 122 123 /** 124 * The name of the attribute used to specify the path to a file that contains 125 * the passphrase to use to generate the encryption key. 126 */ 127 @NotNull private static final String ATTR_ENCRYPTION_PASSPHRASE_FILE = 128 "ds-task-restore-encryption-passphrase-file"; 129 130 131 132 /** 133 * The name of the attribute used to indicate whether to only verify the 134 * backup but not actually restore it. 135 */ 136 @NotNull private static final String ATTR_VERIFY_ONLY = 137 "ds-task-restore-verify-only"; 138 139 140 141 /** 142 * The name of the object class used in restore task entries. 143 */ 144 @NotNull private static final String OC_RESTORE_TASK = "ds-task-restore"; 145 146 147 148 /** 149 * The task property for the backup directory. 150 */ 151 @NotNull private static final TaskProperty PROPERTY_BACKUP_DIRECTORY = 152 new TaskProperty(ATTR_BACKUP_DIRECTORY, 153 INFO_DISPLAY_NAME_BACKUP_DIRECTORY.get(), 154 INFO_DESCRIPTION_BACKUP_DIRECTORY_RESTORE.get(), 155 String.class, true, false, false); 156 157 158 159 /** 160 * The task property for the backup ID. 161 */ 162 @NotNull private static final TaskProperty PROPERTY_BACKUP_ID = 163 new TaskProperty(ATTR_BACKUP_ID, INFO_DISPLAY_NAME_BACKUP_ID.get(), 164 INFO_DESCRIPTION_BACKUP_ID_RESTORE.get(), String.class, 165 false, false, true); 166 167 168 169 /** 170 * The task property that will be used for the encryption passphrase file. 171 */ 172 @NotNull private static final TaskProperty 173 PROPERTY_ENCRYPTION_PASSPHRASE_FILE = new TaskProperty( 174 ATTR_ENCRYPTION_PASSPHRASE_FILE, 175 INFO_DISPLAY_NAME_ENCRYPTION_PASSPHRASE_FILE.get(), 176 INFO_DESCRIPTION_ENCRYPTION_PASSPHRASE_FILE.get(), 177 String.class, false, false, true); 178 179 180 181 /** 182 * The task property for the verify only flag. 183 */ 184 @NotNull private static final TaskProperty PROPERTY_VERIFY_ONLY = 185 new TaskProperty(ATTR_VERIFY_ONLY, INFO_DISPLAY_NAME_VERIFY_ONLY.get(), 186 INFO_DESCRIPTION_VERIFY_ONLY.get(), Boolean.class, 187 false, false, false); 188 189 190 191 /** 192 * The serial version UID for this serializable class. 193 */ 194 private static final long serialVersionUID = -8441221098187125379L; 195 196 197 198 // Indicates whether to only verify the backup without restoring it. 199 private final boolean verifyOnly; 200 201 // The path to the backup directory containing the backup to restore. 202 @NotNull private final String backupDirectory; 203 204 // The path to a file containing the passphrase to use to generate the 205 // encryption key. 206 @Nullable private final String encryptionPassphraseFile; 207 208 // The backup ID of the backup to restore. 209 @Nullable private final String backupID; 210 211 212 213 /** 214 * Creates a new uninitialized restore task instance which should only be used 215 * for obtaining general information about this task, including the task name, 216 * description, and supported properties. Attempts to use a task created with 217 * this constructor for any other reason will likely fail. 218 */ 219 public RestoreTask() 220 { 221 verifyOnly = false; 222 backupDirectory = null; 223 backupID = null; 224 encryptionPassphraseFile = null; 225 } 226 227 228 229 /** 230 * Creates a new restore task with the provided information. 231 * 232 * @param taskID The task ID to use for this task. If it is 233 * {@code null} then a UUID will be generated for use 234 * as the task ID. 235 * @param backupDirectory The path to the directory on the server containing 236 * the backup to restore. It may be an absolute path 237 * or relative to the server root directory. It must 238 * not be {@code null}. 239 * @param backupID The backup ID of the backup to restore. If this 240 * is {@code null} then the most recent backup in the 241 * specified backup directory will be restored. 242 * @param verifyOnly Indicates whether to only verify the backup 243 * without restoring it. 244 */ 245 public RestoreTask(@Nullable final String taskID, 246 @NotNull final String backupDirectory, 247 @Nullable final String backupID, 248 final boolean verifyOnly) 249 { 250 this(taskID, backupDirectory, backupID, verifyOnly, null, null, null, null, 251 null); 252 } 253 254 255 256 /** 257 * Creates a new restore task with the provided information. 258 * 259 * @param taskID The task ID to use for this task. If it is 260 * {@code null} then a UUID will be generated 261 * for use as the task ID. 262 * @param backupDirectory The path to the directory on the server 263 * containing the backup to restore. It may 264 * be an absolute path or relative to the 265 * server root directory. It must not be 266 * {@code null}. 267 * @param backupID The backup ID of the backup to restore. If 268 * this is {@code null} then the most recent 269 * backup in the specified backup directory 270 * will be restored. 271 * @param verifyOnly Indicates whether to only verify the backup 272 * without restoring it. 273 * @param scheduledStartTime The time that this task should start 274 * running. 275 * @param dependencyIDs The list of task IDs that will be required 276 * to complete before this task will be 277 * eligible to start. 278 * @param failedDependencyAction Indicates what action should be taken if 279 * any of the dependencies for this task do 280 * not complete successfully. 281 * @param notifyOnCompletion The list of e-mail addresses of individuals 282 * that should be notified when this task 283 * completes. 284 * @param notifyOnError The list of e-mail addresses of individuals 285 * that should be notified if this task does 286 * not complete successfully. 287 */ 288 public RestoreTask(@Nullable final String taskID, 289 @NotNull final String backupDirectory, 290 @Nullable final String backupID, 291 final boolean verifyOnly, 292 @Nullable final Date scheduledStartTime, 293 @Nullable final List<String> dependencyIDs, 294 @Nullable final FailedDependencyAction failedDependencyAction, 295 @Nullable final List<String> notifyOnCompletion, 296 @Nullable final List<String> notifyOnError) 297 { 298 this(taskID, backupDirectory, backupID, verifyOnly, null, 299 scheduledStartTime, dependencyIDs, failedDependencyAction, 300 notifyOnCompletion, notifyOnError); 301 } 302 303 304 305 /** 306 * Creates a new restore task with the provided information. 307 * 308 * @param taskID The task ID to use for this task. If it 309 * is {@code null} then a UUID will be 310 * generated for use as the task ID. 311 * @param backupDirectory The path to the directory on the server 312 * containing the backup to restore. It may 313 * be an absolute path or relative to the 314 * server root directory. It must not be 315 * {@code null}. 316 * @param backupID The backup ID of the backup to restore. 317 * If this is {@code null} then the most 318 * recent backup in the specified backup 319 * directory will be restored. 320 * @param verifyOnly Indicates whether to only verify the 321 * backup without restoring it. 322 * @param encryptionPassphraseFile The path to a file containing the 323 * passphrase to use to generate the 324 * encryption key. It amy be {@code null} 325 * if the backup is not to be encrypted, or 326 * if the key should be obtained in some 327 * other way. 328 * @param scheduledStartTime The time that this task should start 329 * running. 330 * @param dependencyIDs The list of task IDs that will be 331 * required to complete before this task 332 * will be eligible to start. 333 * @param failedDependencyAction Indicates what action should be taken if 334 * any of the dependencies for this task do 335 * not complete successfully. 336 * @param notifyOnCompletion The list of e-mail addresses of 337 * individuals that should be notified when 338 * this task completes. 339 * @param notifyOnError The list of e-mail addresses of 340 * individuals that should be notified if 341 * this task does not complete successfully. 342 */ 343 public RestoreTask(@Nullable final String taskID, 344 @NotNull final String backupDirectory, 345 @Nullable final String backupID, 346 final boolean verifyOnly, 347 @Nullable final String encryptionPassphraseFile, 348 @Nullable final Date scheduledStartTime, 349 @Nullable final List<String> dependencyIDs, 350 @Nullable final FailedDependencyAction failedDependencyAction, 351 @Nullable final List<String> notifyOnCompletion, 352 @Nullable final List<String> notifyOnError) 353 { 354 this(taskID, backupDirectory, backupID, verifyOnly, 355 encryptionPassphraseFile, scheduledStartTime, dependencyIDs, 356 failedDependencyAction, null, notifyOnCompletion, null, 357 notifyOnError, null, null, null); 358 } 359 360 361 362 /** 363 * Creates a new restore task with the provided information. 364 * 365 * @param taskID The task ID to use for this task. If it 366 * is {@code null} then a UUID will be 367 * generated for use as the task ID. 368 * @param backupDirectory The path to the directory on the server 369 * containing the backup to restore. It may 370 * be an absolute path or relative to the 371 * server root directory. It must not be 372 * {@code null}. 373 * @param backupID The backup ID of the backup to restore. 374 * If this is {@code null} then the most 375 * recent backup in the specified backup 376 * directory will be restored. 377 * @param verifyOnly Indicates whether to only verify the 378 * backup without restoring it. 379 * @param encryptionPassphraseFile The path to a file containing the 380 * passphrase to use to generate the 381 * encryption key. It amy be {@code null} 382 * if the backup is not to be encrypted, or 383 * if the key should be obtained in some 384 * other way. 385 * @param scheduledStartTime The time that this task should start 386 * running. 387 * @param dependencyIDs The list of task IDs that will be 388 * required to complete before this task 389 * will be eligible to start. 390 * @param failedDependencyAction Indicates what action should be taken if 391 * any of the dependencies for this task do 392 * not complete successfully. 393 * @param notifyOnStart The list of e-mail addresses of individuals 394 * that should be notified when this task 395 * starts running. 396 * @param notifyOnCompletion The list of e-mail addresses of individuals 397 * that should be notified when this task 398 * completes. 399 * @param notifyOnSuccess The list of e-mail addresses of individuals 400 * that should be notified if this task 401 * completes successfully. 402 * @param notifyOnError The list of e-mail addresses of individuals 403 * that should be notified if this task does 404 * not complete successfully. 405 * @param alertOnStart Indicates whether the server should send an 406 * alert notification when this task starts. 407 * @param alertOnSuccess Indicates whether the server should send an 408 * alert notification if this task completes 409 * successfully. 410 * @param alertOnError Indicates whether the server should send an 411 * alert notification if this task fails to 412 * complete successfully. 413 */ 414 public RestoreTask(@Nullable final String taskID, 415 @NotNull final String backupDirectory, 416 @Nullable final String backupID, 417 final boolean verifyOnly, 418 @Nullable final String encryptionPassphraseFile, 419 @Nullable final Date scheduledStartTime, 420 @Nullable final List<String> dependencyIDs, 421 @Nullable final FailedDependencyAction failedDependencyAction, 422 @Nullable final List<String> notifyOnStart, 423 @Nullable final List<String> notifyOnCompletion, 424 @Nullable final List<String> notifyOnSuccess, 425 @Nullable final List<String> notifyOnError, 426 @Nullable final Boolean alertOnStart, 427 @Nullable final Boolean alertOnSuccess, 428 @Nullable final Boolean alertOnError) 429 { 430 super(taskID, RESTORE_TASK_CLASS, scheduledStartTime, 431 dependencyIDs, failedDependencyAction, notifyOnStart, 432 notifyOnCompletion, notifyOnSuccess, notifyOnError, alertOnStart, 433 alertOnSuccess, alertOnError); 434 435 Validator.ensureNotNull(backupDirectory); 436 437 this.backupDirectory = backupDirectory; 438 this.backupID = backupID; 439 this.verifyOnly = verifyOnly; 440 this.encryptionPassphraseFile = encryptionPassphraseFile; 441 } 442 443 444 445 /** 446 * Creates a new restore task from the provided entry. 447 * 448 * @param entry The entry to use to create this restore task. 449 * 450 * @throws TaskException If the provided entry cannot be parsed as a restore 451 * task entry. 452 */ 453 public RestoreTask(@NotNull final Entry entry) 454 throws TaskException 455 { 456 super(entry); 457 458 459 // Get the backup directory. It must be present. 460 backupDirectory = entry.getAttributeValue(ATTR_BACKUP_DIRECTORY); 461 if (backupDirectory == null) 462 { 463 throw new TaskException(ERR_RESTORE_NO_BACKUP_DIRECTORY.get( 464 getTaskEntryDN())); 465 } 466 467 468 // Get the backup ID. It may be absent. 469 backupID = entry.getAttributeValue(ATTR_BACKUP_ID); 470 471 472 // Get the verifyOnly flag. It may be absent. 473 verifyOnly = parseBooleanValue(entry, ATTR_VERIFY_ONLY, false); 474 475 476 // Get the path to the encryption passphrase file. It may be absent. 477 encryptionPassphraseFile = 478 entry.getAttributeValue(ATTR_ENCRYPTION_PASSPHRASE_FILE); 479 } 480 481 482 483 /** 484 * Creates a new restore task from the provided set of task properties. 485 * 486 * @param properties The set of task properties and their corresponding 487 * values to use for the task. It must not be 488 * {@code null}. 489 * 490 * @throws TaskException If the provided set of properties cannot be used to 491 * create a valid restore task. 492 */ 493 public RestoreTask(@NotNull final Map<TaskProperty,List<Object>> properties) 494 throws TaskException 495 { 496 super(RESTORE_TASK_CLASS, properties); 497 498 boolean v = false; 499 String b = null; 500 String f = null; 501 String i = null; 502 503 for (final Map.Entry<TaskProperty,List<Object>> entry : 504 properties.entrySet()) 505 { 506 final TaskProperty p = entry.getKey(); 507 final String attrName = p.getAttributeName(); 508 final List<Object> values = entry.getValue(); 509 510 if (attrName.equalsIgnoreCase(ATTR_BACKUP_DIRECTORY)) 511 { 512 b = parseString(p, values, b); 513 } 514 else if (attrName.equalsIgnoreCase(ATTR_BACKUP_ID)) 515 { 516 i = parseString(p, values, i); 517 } 518 else if (attrName.equalsIgnoreCase(ATTR_VERIFY_ONLY)) 519 { 520 v = parseBoolean(p, values, v); 521 } 522 else if (attrName.equalsIgnoreCase(ATTR_ENCRYPTION_PASSPHRASE_FILE)) 523 { 524 f = parseString(p, values, f); 525 } 526 } 527 528 if (b == null) 529 { 530 throw new TaskException(ERR_RESTORE_NO_BACKUP_DIRECTORY.get( 531 getTaskEntryDN())); 532 } 533 534 backupDirectory = b; 535 backupID = i; 536 verifyOnly = v; 537 encryptionPassphraseFile = f; 538 } 539 540 541 542 /** 543 * {@inheritDoc} 544 */ 545 @Override() 546 @NotNull() 547 public String getTaskName() 548 { 549 return INFO_TASK_NAME_RESTORE.get(); 550 } 551 552 553 554 /** 555 * {@inheritDoc} 556 */ 557 @Override() 558 @NotNull() 559 public String getTaskDescription() 560 { 561 return INFO_TASK_DESCRIPTION_RESTORE.get(); 562 } 563 564 565 566 /** 567 * Retrieves the path to the backup directory which contains the backup to 568 * restore. It may be either an absolute path or one that is relative to the 569 * server root. 570 * 571 * @return The path to the backup directory which contains the backup to 572 * restore. 573 */ 574 @NotNull() 575 public String getBackupDirectory() 576 { 577 return backupDirectory; 578 } 579 580 581 582 /** 583 * Retrieves the backup ID of the backup to restore. 584 * 585 * @return The backup ID of the backup to restore, or {@code null} if the 586 * most recent backup in the backup directory should be restored. 587 */ 588 @Nullable() 589 public String getBackupID() 590 { 591 return backupID; 592 } 593 594 595 596 /** 597 * Indicates whether the backup should only be verified without actually being 598 * restored. 599 * 600 * @return {@code true} if the backup should be verified but not restored, or 601 * {@code false} if it should be restored. 602 */ 603 public boolean verifyOnly() 604 { 605 return verifyOnly; 606 } 607 608 609 610 /** 611 * Retrieves the path to a file that contains the passphrase to use to 612 * generate the encryption key. 613 * 614 * @return The path to a file that contains the passphrase to use to 615 * generate the encryption key, or {@code null} if the backup is 616 * not encrypted or if the encryption key should be obtained through 617 * some other means. 618 */ 619 @Nullable() 620 public String getEncryptionPassphraseFile() 621 { 622 return encryptionPassphraseFile; 623 } 624 625 626 627 /** 628 * {@inheritDoc} 629 */ 630 @Override() 631 @NotNull() 632 protected List<String> getAdditionalObjectClasses() 633 { 634 return Collections.singletonList(OC_RESTORE_TASK); 635 } 636 637 638 639 /** 640 * {@inheritDoc} 641 */ 642 @Override() 643 @NotNull() 644 protected List<Attribute> getAdditionalAttributes() 645 { 646 final ArrayList<Attribute> attrs = new ArrayList<>(10); 647 648 attrs.add(new Attribute(ATTR_BACKUP_DIRECTORY, backupDirectory)); 649 attrs.add(new Attribute(ATTR_VERIFY_ONLY, String.valueOf(verifyOnly))); 650 651 if (backupID != null) 652 { 653 attrs.add(new Attribute(ATTR_BACKUP_ID, backupID)); 654 } 655 656 if (encryptionPassphraseFile != null) 657 { 658 attrs.add(new Attribute(ATTR_ENCRYPTION_PASSPHRASE_FILE, 659 encryptionPassphraseFile)); 660 } 661 662 return attrs; 663 } 664 665 666 667 /** 668 * {@inheritDoc} 669 */ 670 @Override() 671 @NotNull() 672 public List<TaskProperty> getTaskSpecificProperties() 673 { 674 final List<TaskProperty> propList = Arrays.asList( 675 PROPERTY_BACKUP_DIRECTORY, 676 PROPERTY_BACKUP_ID, 677 PROPERTY_VERIFY_ONLY, 678 PROPERTY_ENCRYPTION_PASSPHRASE_FILE); 679 680 return Collections.unmodifiableList(propList); 681 } 682 683 684 685 /** 686 * {@inheritDoc} 687 */ 688 @Override() 689 @NotNull() 690 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 691 { 692 final LinkedHashMap<TaskProperty,List<Object>> props = 693 new LinkedHashMap<>(StaticUtils.computeMapCapacity(10)); 694 695 props.put(PROPERTY_BACKUP_DIRECTORY, 696 Collections.<Object>singletonList(backupDirectory)); 697 698 if (backupID == null) 699 { 700 props.put(PROPERTY_BACKUP_ID, Collections.emptyList()); 701 } 702 else 703 { 704 props.put(PROPERTY_BACKUP_ID, 705 Collections.<Object>singletonList(backupID)); 706 } 707 708 props.put(PROPERTY_VERIFY_ONLY, 709 Collections.<Object>singletonList(verifyOnly)); 710 711 if (encryptionPassphraseFile == null) 712 { 713 props.put(PROPERTY_ENCRYPTION_PASSPHRASE_FILE, Collections.emptyList()); 714 } 715 else 716 { 717 props.put(PROPERTY_ENCRYPTION_PASSPHRASE_FILE, 718 Collections.<Object>singletonList(encryptionPassphraseFile)); 719 } 720 721 props.putAll(super.getTaskPropertyValues()); 722 return Collections.unmodifiableMap(props); 723 } 724}