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