summaryrefslogtreecommitdiffstats
path: root/install
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2013-03-13 09:36:41 -0400
committerRob Crittenden <rcritten@redhat.com>2013-04-12 09:59:17 -0400
commitc8694cb19f2b0bd20a0b3fc9df7aacec3b23a928 (patch)
treec13c5965a41c328e9cae04530e550522ae49a678 /install
parentc0cdba78b01317a9ea5c423eda548a69ee046e26 (diff)
downloadfreeipa-c8694cb19f2b0bd20a0b3fc9df7aacec3b23a928.tar.gz
freeipa-c8694cb19f2b0bd20a0b3fc9df7aacec3b23a928.tar.xz
freeipa-c8694cb19f2b0bd20a0b3fc9df7aacec3b23a928.zip
Full system backup and restore
This will allow one to backup and restore the IPA files and data. This does not cover individual entry restoration. http://freeipa.org/page/V3/Backup_and_Restore https://fedorahosted.org/freeipa/ticket/3128
Diffstat (limited to 'install')
-rw-r--r--install/tools/Makefile.am2
-rwxr-xr-xinstall/tools/ipa-backup23
-rwxr-xr-xinstall/tools/ipa-csreplica-manage150
-rwxr-xr-xinstall/tools/ipa-replica-manage4
-rwxr-xr-xinstall/tools/ipa-restore23
-rw-r--r--install/tools/man/Makefile.am5
-rw-r--r--install/tools/man/ipa-backup.184
-rw-r--r--install/tools/man/ipa-restore.1105
8 files changed, 278 insertions, 118 deletions
diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am
index 7f1504cd5..76cd1196b 100644
--- a/install/tools/Makefile.am
+++ b/install/tools/Makefile.am
@@ -22,6 +22,8 @@ sbin_SCRIPTS = \
ipa-ldap-updater \
ipa-upgradeconfig \
ipa-compliance \
+ ipa-backup \
+ ipa-restore \
$(NULL)
EXTRA_DIST = \
diff --git a/install/tools/ipa-backup b/install/tools/ipa-backup
new file mode 100755
index 000000000..5bcaa1d8c
--- /dev/null
+++ b/install/tools/ipa-backup
@@ -0,0 +1,23 @@
+#! /usr/bin/python -E
+# Authors: Rob Crittenden <rcritten@redhat.com>
+#
+# Copyright (C) 2013 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from ipaserver.install.ipa_backup import Backup
+
+Backup.run_cli()
diff --git a/install/tools/ipa-csreplica-manage b/install/tools/ipa-csreplica-manage
index cd2fd010b..b9fa05f94 100755
--- a/install/tools/ipa-csreplica-manage
+++ b/install/tools/ipa-csreplica-manage
@@ -46,109 +46,6 @@ commands = {
}
-def get_cs_replication_manager(realm, host, dirman_passwd):
- """Get a CSReplicationManager for a remote host
-
- Detects if the host has a merged database, connects to appropriate port.
- """
-
- # Try merged database port first. If it has the ipaca tree, return
- # corresponding replication manager
- # If we can't connect to it at all, we're not dealing with an IPA master
- # anyway; let the exception propagate up
- # Fall back to the old PKI-only DS port. Check that it has the ipaca tree
- # (IPA with merged DB theoretically leaves port 7389 free for anyone).
- # If it doesn't, raise exception.
- ports = [
- dogtag.Dogtag10Constants.DS_PORT,
- dogtag.Dogtag9Constants.DS_PORT,
- ]
- for port in ports:
- root_logger.debug('Looking for PKI DS on %s:%s' % (host, port))
- replication_manager = CSReplicationManager(
- realm, host, dirman_passwd, port)
- if replication_manager.has_ipaca():
- root_logger.debug('PKI DS found on %s:%s' % (host, port))
- return replication_manager
- else:
- root_logger.debug('PKI tree not found on %s:%s' % (host, port))
- sys.exit('Cannot reach PKI DS at %s on ports %s' % (host, ports))
-
-
-class CSReplicationManager(replication.ReplicationManager):
- """ReplicationManager specific to CA agreements
-
- Note that in most cases we don't know if we're connecting to an old-style
- separate PKI DS, or to a host with a merged DB.
- Use the get_cs_replication_manager function to determine this and return
- an appropriate CSReplicationManager.
- """
-
- def __init__(self, realm, hostname, dirman_passwd, port):
- super(CSReplicationManager, self).__init__(
- realm, hostname, dirman_passwd, port, starttls=True)
- self.suffix = DN(('o', 'ipaca'))
- self.hostnames = [] # set before calling or agreement_dn() will fail
-
- def agreement_dn(self, hostname, master=None):
- """
- Construct a dogtag replication agreement name. This needs to be much
- more agressive than the IPA replication agreements because the name
- is different on each side.
-
- hostname is the local hostname, not the remote one, for both sides
-
- NOTE: The agreement number is hardcoded in dogtag as well
-
- TODO: configurable instance name
- """
- dn = None
- cn = None
- instance_name = dogtag.configured_constants(api).PKI_INSTANCE_NAME
-
- # if master is not None we know what dn to return:
- if master is not None:
- if master is True:
- name = "master"
- else:
- name = "clone"
- cn="%sAgreement1-%s-%s" % (name, hostname, instance_name)
- dn = DN(('cn', cn), self.replica_dn())
- return (cn, dn)
-
- for host in self.hostnames:
- for master in ["master", "clone"]:
- try:
- cn="%sAgreement1-%s-%s" % (master, host, instance_name)
- dn = DN(('cn', cn), self.replica_dn())
- self.conn.get_entry(dn)
- return (cn, dn)
- except errors.NotFound:
- dn = None
- cn = None
-
- raise errors.NotFound(reason='No agreement found for %s' % hostname)
-
- def delete_referral(self, hostname, port):
- dn = DN(('cn', self.suffix), ('cn', 'mapping tree'), ('cn', 'config'))
- entry = self.conn.get_entry(dn)
- try:
- # TODO: should we detect proto somehow ?
- entry['nsslapd-referral'].remove('ldap://%s/%s' %
- (ipautil.format_netloc(hostname, port), self.suffix))
- self.conn.update_entry(entry)
- except Exception, e:
- root_logger.debug("Failed to remove referral value: %s" % e)
-
- def has_ipaca(self):
- try:
- entry = self.conn.get_entry(self.suffix)
- except errors.NotFound:
- return False
- else:
- return True
-
-
def parse_options():
from optparse import OptionParser
@@ -219,7 +116,11 @@ def list_replicas(realm, host, replica, dirman_passwd, verbose):
print '%s: %s' % (k, p[0])
return
- repl = get_cs_replication_manager(realm, replica, dirman_passwd)
+ try:
+ repl = replication.get_cs_replication_manager(realm, replica, dirman_passwd)
+ except Exception, e:
+ sys.exit(str(e))
+
entries = repl.find_replication_agreements()
for entry in entries:
@@ -242,7 +143,7 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False):
repl2 = None
try:
- repl1 = get_cs_replication_manager(realm, replica1, dirman_passwd)
+ repl1 = replication.get_cs_replication_manager(realm, replica1, dirman_passwd)
repl1.hostnames = [replica1, replica2]
@@ -266,7 +167,7 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False):
sys.exit("Failed to get data from '%s': %s" % (replica1, e))
try:
- repl2 = get_cs_replication_manager(realm, replica2, dirman_passwd)
+ repl2 = replication.get_cs_replication_manager(realm, replica2, dirman_passwd)
repl2.hostnames = [replica1, replica2]
@@ -335,8 +236,8 @@ def del_master(realm, hostname, options):
# 1. Connect to the local dogtag DS server
try:
- thisrepl = get_cs_replication_manager(realm, options.host,
- options.dirman_passwd)
+ thisrepl = replication.get_cs_replication_manager(realm, options.host,
+ options.dirman_passwd)
except Exception, e:
sys.exit("Failed to connect to server %s: %s" % (options.host, e))
@@ -346,8 +247,8 @@ def del_master(realm, hostname, options):
# 3. Connect to the dogtag DS to be removed.
try:
- delrepl = get_cs_replication_manager(realm, hostname,
- options.dirman_passwd)
+ delrepl = replication.get_cs_replication_manager(realm, hostname,
+ options.dirman_passwd)
except Exception, e:
if not options.force:
print "Unable to delete replica %s: %s" % (hostname, e)
@@ -371,7 +272,11 @@ def del_master(realm, hostname, options):
sys.exit("There were issues removing a connection: %s" % e)
def add_link(realm, replica1, replica2, dirman_passwd, options):
- repl2 = get_cs_replication_manager(realm, replica2, dirman_passwd)
+ try:
+ repl2 = replication.get_cs_replication_manager(realm, replica2,
+ dirman_passwd)
+ except Exception, e:
+ sys.exit(str(e))
try:
conn = ipaldap.IPAdmin(replica2, 636, cacert=CACERT)
conn.do_simple_bind(bindpw=dirman_passwd)
@@ -388,7 +293,8 @@ def add_link(realm, replica1, replica2, dirman_passwd, options):
sys.exit("Failed to get data while trying to bind to '%s': %s" % (replica1, str(e)))
try:
- repl1 = get_cs_replication_manager(realm, replica1, dirman_passwd)
+ repl1 = replication.get_cs_replication_manager(realm, replica1,
+ dirman_passwd)
entries = repl1.find_replication_agreements()
for e in entries:
if e.single_value('nsDS5ReplicaHost', None) == replica2:
@@ -414,11 +320,16 @@ def re_initialize(realm, options):
if not options.fromhost:
sys.exit("re-initialize requires the option --from <host name>")
- repl = get_cs_replication_manager(realm, options.fromhost,
- options.dirman_passwd)
-
thishost = installutils.get_fqdn()
+ try:
+ repl = replication.get_cs_replication_manager(realm, options.fromhost,
+ options.dirman_passwd)
+ thisrepl = replication.get_cs_replication_manager(realm, thishost,
+ options.dirman_passwd)
+ except Exception, e:
+ sys.exit(str(e))
+
filter = repl.get_agreement_filter(host=thishost)
try:
entry = repl.conn.get_entries(
@@ -429,16 +340,21 @@ def re_initialize(realm, options):
if len(entry) > 1:
root_logger.error("Found multiple agreements for %s. Only initializing the first one returned: %s" % (thishost, entry[0].dn))
+ repl.hostnames = thisrepl.hostnames = [thishost, options.fromhost]
+ thisrepl.enable_agreement(options.fromhost)
+ repl.enable_agreement(thishost)
+
repl.initialize_replication(entry[0].dn, repl.conn)
repl.wait_for_repl_init(repl.conn, entry[0].dn)
def force_sync(realm, thishost, fromhost, dirman_passwd):
- repl = get_cs_replication_manager(realm, fromhost, dirman_passwd)
try:
+ repl = replication.get_cs_replication_manager(realm, fromhost,
+ dirman_passwd)
repl.force_sync(repl.conn, thishost)
except Exception, e:
- sys.exit(e)
+ sys.exit(str(e))
def main():
options, args = parse_options()
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index 636529caa..956fb2f14 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -827,6 +827,10 @@ def re_initialize(realm, thishost, fromhost, dirman_passwd):
else:
repl = replication.ReplicationManager(realm, fromhost, dirman_passwd)
agreement = repl.get_replication_agreement(thishost)
+
+ thisrepl.enable_agreement(fromhost)
+ repl.enable_agreement(thishost)
+
repl.force_sync(repl.conn, thishost)
repl.initialize_replication(agreement.dn, repl.conn)
diff --git a/install/tools/ipa-restore b/install/tools/ipa-restore
new file mode 100755
index 000000000..604175be2
--- /dev/null
+++ b/install/tools/ipa-restore
@@ -0,0 +1,23 @@
+#! /usr/bin/python -E
+# Authors: Rob Crittenden <rcritten@redhat.com>
+#
+# Copyright (C) 2013 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from ipaserver.install.ipa_restore import Restore
+
+Restore.run_cli()
diff --git a/install/tools/man/Makefile.am b/install/tools/man/Makefile.am
index 8d5d416d9..a1bf076bf 100644
--- a/install/tools/man/Makefile.am
+++ b/install/tools/man/Makefile.am
@@ -19,7 +19,10 @@ man1_MANS = \
ipa-compat-manage.1 \
ipa-nis-manage.1 \
ipa-managed-entries.1 \
- ipa-compliance.1
+ ipa-compliance.1 \
+ ipa-backup.1 \
+ ipa-restore.1 \
+ $(NULL)
man8_MANS = \
ipactl.8 \
diff --git a/install/tools/man/ipa-backup.1 b/install/tools/man/ipa-backup.1
new file mode 100644
index 000000000..ff9759ec7
--- /dev/null
+++ b/install/tools/man/ipa-backup.1
@@ -0,0 +1,84 @@
+.\" A man page for ipa-backup
+.\" Copyright (C) 2013 Red Hat, Inc.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation, either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa-backup" "1" "Mar 22 2013" "FreeIPA" "FreeIPA Manual Pages"
+.SH "NAME"
+ipa\-backup \- Back up an IPA master
+.SH "SYNOPSIS"
+ipa\-backup [\fIOPTION\fR]...
+.SH "DESCRIPTION"
+Two kinds of backups: full and data\-only.
+.TP
+The back up is optionally encrypted using either the default root GPG key or a named key. No passphrase is supported.
+.TP
+Backups are stored in a subdirectory in /var/lib/ipa/backup.
+.TP
+The naming convention for full backups is ipa\-full\-YEAR\-MM\-DD\-HH\-MM\-SS in the GMT time zone.
+.TP
+The naming convention for data backups is ipa\-data\-YEAR\-MM\-DD\-HH\-MM\-SS In the GMT time zone.
+.TP
+Within the subdirectory is file, header, that describes the back up including the type, system, date of backup, the version of IPA, the version of the backup and the services on the master.
+.TP
+A backup can not be restored on another host.
+.TP
+A backup can not be restored in a different version of IPA.
+.SH "OPTIONS"
+.TP
+\fB\-\-data\fR
+Back up data only. The default is to back up all IPA files plus data.
+.TP
+\fB\-\-gpg\fR
+Encrypt the back up file.
+.TP
+\fB\-\-gpg\-keyring\fR=\fIGPG_KEYRING\fR
+The full path to a GPG keyring. The keyring consists of two files, a public and a private key (.sec and .pub respectively). Specify the path without an extension.
+.TP
+\fB\-\-logs\fR
+Include the IPA service log files in the backup.
+.TP
+\fB\-\-online\fR
+Perform the backup on\-line. Requires the \-\-data option.
+.TP
+\fB\-\-v\fR, \fB\-\-verbose\fR
+Print debugging information
+.TP
+\fB\-d\fR, \fB\-\-debug\fR
+Alias for \-\-verbose
+.TP
+\fB\-q\fR, \fB\-\-quiet\fR
+Output only errors
+.TP
+\fB\-\-log\-file\fR=\fIFILE\fR
+Log to the given file
+.SH "EXIT STATUS"
+0 if the command was successful
+
+1 if an error occurred
+.SH "FILES"
+.PP
+\fI/var/lib/ipa/backup\fR
+.RS 4
+The default directory for storing backup files.
+.RE
+.PP
+\fl/var/log/ipabackup.log\fR
+.RS 4
+The log file for backups
+.PP
+.SH "SEE ALSO"
+ipa\-restore(1).
diff --git a/install/tools/man/ipa-restore.1 b/install/tools/man/ipa-restore.1
new file mode 100644
index 000000000..31734b259
--- /dev/null
+++ b/install/tools/man/ipa-restore.1
@@ -0,0 +1,105 @@
+.\" A man page for ipa-restore
+.\" Copyright (C) 2013 Red Hat, Inc.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation, either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
+.\"
+.\" Author: Rob Crittenden <rcritten@redhat.com>
+.\"
+.TH "ipa-restore" "1" "Mar 22 2013" "FreeIPA" "FreeIPA Manual Pages"
+.SH "NAME"
+ipa\-restore \- Restore an IPA master
+.SH "SYNOPSIS"
+ipa\-restore [\fIOPTION\fR]... BACKUP
+.SH "DESCRIPTION"
+Only the name of the backup needs to be passed in, not the full path. Backups are stored in a subdirectory in /var/lib/ipa/backup. If a backup is in another location then the full path must be provided.
+.TP
+The naming convention for full backups is ipa\-full\-YEAR\-MM\-DD\-HH\-MM\-SS in the GMT time zone.
+.TP
+The naming convention for data backups is ipa\-data\-YEAR\-MM\-DD\-HH\-MM\-SS In the GMT time zone.
+.TP
+The type of backup is automatically detected. A data restore can be done from either type.
+.TP
+\fBWARNING\fR: A full restore will restore files like /etc/passwd, /etc/group, /etc/resolv.conf as well. Any file that IPA may have touched is backed up and restored.
+.TP
+An encrypted backup is also automatically detected and the root keyring is used by default. The \-\-keyring option can be used to define the full path to the private and public keys.
+.TP
+Within the subdirectory is file, header, that describes the back up including the type, system, date of backup, the version of IPA, the version of the backup and the services on the master.
+.TP
+A backup can not be restored on another host.
+.TP
+A backup can not be restored in a different version of IPA.
+.TP
+Restoring from backup sets the server as the new data master. All other masters will need to be re\-initialized. The first step in restoring a backup is to disable replication on all the other masters. This is to prevent the changelog from overwriting the data in the backup.
+.TP
+Use the ipa\-replica\-manage and ipa\-csreplica\-manage commands to re\-initialize other masters. ipa\-csreplica\-manage only needs to be executed on masters that have a CA installed.
+.SH "REPLICATION"
+The restoration on other masters needs to be done carefully, to match the replication topology, working outward from the restored master. For example, if your topology is A <\-> B <\-> C and you restored master A you would restore B first, then C.
+.TP
+Replication is disabled on all masters that are available when a restoration is done. If a master is down at the time of the restoration you will need to proceed with extreme caution. If this master is brought back up after the restoration is complete it may send out replication updates that apply the very changes you were trying to back out. The only safe answer is to reinstall the master. This would involve deleting all replication agreements to the master. This could have a cascading effect if the master is a hub to other masters. They would need to be connected to other masters before removing the downed master.
+.TP
+If the restore point is from a period prior to a replication agreement then the master will need to be re\-installed. For example, you have masters A and B and you create a backup. You then add master C from B. Then you restore from the backup. The restored data is going to lose the replication agreement to C. The master on C will have a replication agreement pointing to B, but B won't have the reverse agreement. Master C won't be registered as an IPA master. It may be possible to manually correct these and re\-connect C to B but it would be very prone to error.
+.TP
+If re\-initializing on an IPA master version prior to 3.2 then the replication agreements will need to be manually re\-enabled otherwise the re\-initialization will never complete. To manually enable an agreement use ldapsearch to find the agreement name in cn=mapping tree,cn=config. The value of nsds5ReplicaEnabled needs to be on, and enabled on both sides. Remember that CA replication is done through a separate agreement and will need to be updated separately.
+.TP
+If you have older masters you should consider re\-creating them rather than trying to re\-initialize them.
+.SH "OPTIONS"
+.TP
+\fB\-p\fR, \fB\-\-password\fR=\fIPASSWORD\fR
+The Directory Manager password.
+\fB\-\-data\fR
+Restore the data only. The default is to restore everything in the backup.
+.TP
+\fB\-\-gpg\-keyring\fR=\fIGPG_KEYRING\fR
+The full path to a GPG keyring. The keyring consists of two files, a public and a private key (.sec and .pub respectively). Specify the path without an extension.
+.TP
+\fB\-\-no\-logs\fR
+Exclude the IPA service log files in the backup (if they were backed up). Applicable only with a full backup.
+.TP
+\fB\-\-online\fR
+Perform the restore on\-line. Requires the \-\-data option.
+.TP
+\fB\-\-instance\fR=\fIINSTANCE\fR
+The backend to restore within an instance or instances.
+.TP
+Restore only the databases in this 389\-ds instance. The default is to restore all found (at most this is the IPA REALM instance and the PKI\-IPA instance).
+.TP
+\fB\-\-backend\fR=\fIBACKEND\fR
+\fB\-\-v\fR, \fB\-\-verbose\fR
+Print debugging information
+.TP
+\fB\-d\fR, \fB\-\-debug\fR
+Alias for \-\-verbose
+.TP
+\fB\-q\fR, \fB\-\-quiet\fR
+Output only errors
+.TP
+\fB\-\-log\-file\fR=\fIFILE\fR
+Log to the given file
+.SH "EXIT STATUS"
+0 if the command was successful
+
+1 if an error occurred
+.SH "FILES"
+.PP
+\fI/var/lib/ipa/backup\fR
+.RS 4
+The default directory for storing backup files.
+.RE
+.PP
+\fl/var/log/iparestore.log\fR
+.RS 4
+The log file for restoration
+.PP
+.SH "SEE ALSO"
+ipa\-backup(1).