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