Files
freeipa/ipaserver/install/ipa_backup.py
T

639 lines
21 KiB
Python
Raw Normal View History

2013-08-20 13:38:29 +02:00
# Authors: Rob Crittenden <rcritten@redhat.com>
2013-03-13 09:36:41 -04:00
#
# 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/>.
#
2018-05-23 12:33:01 +02:00
from __future__ import absolute_import, print_function
2018-04-05 09:21:16 +02:00
2017-05-23 18:35:57 +02:00
import logging
2018-05-23 12:33:01 +02:00
import optparse # pylint: disable=deprecated-module
2013-03-13 09:36:41 -04:00
import os
import shutil
2018-05-23 12:33:01 +02:00
import sys
2013-03-13 09:36:41 -04:00
import tempfile
import time
import pwd
import six
2016-08-24 13:37:30 +02:00
from ipaplatform.paths import paths
from ipaplatform import services
2013-03-13 09:36:41 -04:00
from ipalib import api, errors
from ipapython import version
from ipapython.ipautil import run, write_tmp_file
2017-11-08 12:10:54 +01:00
from ipapython import admintool, certdb
2013-03-13 09:36:41 -04:00
from ipapython.dn import DN
from ipaserver.install.replication import wait_for_task
from ipaserver.install import installutils
from ipapython import ipaldap
from ipaplatform.constants import constants
from ipaplatform.tasks import tasks
2013-03-13 09:36:41 -04:00
2017-11-08 12:10:54 +01:00
# pylint: disable=import-error
if six.PY3:
# The SafeConfigParser class has been renamed to ConfigParser in Py3
from configparser import ConfigParser as SafeConfigParser
else:
from ConfigParser import SafeConfigParser
# pylint: enable=import-error
2016-08-19 09:23:55 -04:00
ISO8601_DATETIME_FMT = '%Y-%m-%dT%H:%M:%S'
2017-05-23 18:35:57 +02:00
logger = logging.getLogger(__name__)
2013-03-13 09:36:41 -04:00
"""
2018-05-23 12:33:01 +02:00
A test GnuPG key can be generated like this:
2013-03-13 09:36:41 -04:00
# cat >keygen <<EOF
2018-05-23 12:33:01 +02:00
%echo Generating a standard key
Key-Type: RSA
Key-Length: 2048
Name-Real: IPA Backup
Name-Comment: IPA Backup
Name-Email: root@example.com
Expire-Date: 0
Passphrase: SecretPassPhrase42
%commit
%echo done
2013-03-13 09:36:41 -04:00
EOF
2018-05-23 12:33:01 +02:00
# export GNUPGHOME=/root/backup
# mkdir -p $GNUPGHOME
# gpg2 --batch --gen-key keygen
# gpg2 --list-secret-keys
2013-03-13 09:36:41 -04:00
"""
2018-05-23 12:33:01 +02:00
def encrypt_file(filename, remove_original=True):
2013-03-13 09:36:41 -04:00
source = filename
dest = filename + '.gpg'
2018-05-23 12:33:01 +02:00
args = [
paths.GPG2,
'--batch',
'--default-recipient-self',
'--output', dest,
'--encrypt', source,
]
2013-03-13 09:36:41 -04:00
2015-11-25 17:17:18 +01:00
result = run(args, raiseonerr=False)
if result.returncode != 0:
raise admintool.ScriptError('gpg failed: %s' % result.error_log)
2013-03-13 09:36:41 -04:00
if remove_original:
os.unlink(source)
return dest
class Backup(admintool.AdminTool):
command_name = 'ipa-backup'
log_file_name = paths.IPABACKUP_LOG
2013-03-13 09:36:41 -04:00
usage = "%prog [options]"
description = "Back up IPA files and databases."
dirs = (paths.IPA_HTML_DIR,
paths.ROOT_PKI,
paths.PKI_TOMCAT,
paths.SYSCONFIG_PKI,
paths.VAR_LIB_PKI_DIR,
paths.SYSRESTORE,
paths.IPA_CLIENT_SYSRESTORE,
paths.IPA_DNSSEC_DIR,
paths.SSSD_PUBCONF_KRB5_INCLUDE_D_DIR,
paths.AUTHCONFIG_LAST,
paths.VAR_LIB_CERTMONGER_DIR,
paths.VAR_LIB_IPA,
paths.VAR_RUN_DIRSRV_DIR,
paths.DIRSRV_LOCK_DIR,
2013-03-13 09:36:41 -04:00
)
files = (
paths.NAMED_CONF,
paths.NAMED_KEYTAB,
paths.RESOLV_CONF,
paths.SYSCONFIG_PKI_TOMCAT,
paths.SYSCONFIG_DIRSRV,
paths.SYSCONFIG_KRB5KDC_DIR,
2014-10-20 11:03:33 +02:00
paths.SYSCONFIG_IPA_DNSKEYSYNCD,
paths.SYSCONFIG_IPA_ODS_EXPORTER,
2014-10-20 11:03:33 +02:00
paths.SYSCONFIG_NAMED,
paths.SYSCONFIG_ODS,
paths.ETC_SYSCONFIG_AUTHCONFIG,
paths.IPA_NSSDB_PWDFILE_TXT,
2014-11-10 16:24:22 +00:00
paths.IPA_P11_KIT,
paths.SYSTEMWIDE_IPA_CA_CRT,
paths.NSSWITCH_CONF,
paths.KRB5_KEYTAB,
paths.SSSD_CONF,
paths.OPENLDAP_LDAP_CONF,
paths.LIMITS_CONF,
paths.HTTPD_PASSWORD_CONF,
2016-11-29 11:10:22 -05:00
paths.HTTP_KEYTAB,
2015-06-23 17:01:00 +02:00
paths.HTTPD_IPA_KDCPROXY_CONF,
paths.HTTPD_IPA_PKI_PROXY_CONF,
paths.HTTPD_IPA_REWRITE_CONF,
paths.HTTPD_SSL_CONF,
2018-05-21 13:46:42 +03:00
paths.HTTPD_SSL_SITE_CONF,
paths.HTTPD_CERT_FILE,
paths.HTTPD_KEY_FILE,
paths.HTTPD_IPA_CONF,
paths.SSHD_CONFIG,
paths.SSH_CONFIG,
paths.KRB5_CONF,
paths.KDC_CA_BUNDLE_PEM,
paths.CA_BUNDLE_PEM,
2016-11-22 14:42:33 +01:00
paths.IPA_CA_CRT,
paths.IPA_DEFAULT_CONF,
paths.DS_KEYTAB,
paths.CHRONY_CONF,
paths.SMB_CONF,
paths.SAMBA_KEYTAB,
2014-10-01 14:59:46 -04:00
paths.DOGTAG_ADMIN_P12,
paths.RA_AGENT_PEM,
2017-01-13 09:08:42 +01:00
paths.RA_AGENT_KEY,
paths.CACERT_P12,
2017-02-10 10:41:12 +01:00
paths.KRACERT_P12,
paths.KRB5KDC_KDC_CONF,
2017-03-14 13:27:39 +01:00
paths.KDC_CERT,
paths.KDC_KEY,
2017-03-27 10:44:56 +02:00
paths.CACERT_PEM,
paths.SYSTEMD_IPA_SERVICE,
2017-03-16 10:22:59 +01:00
paths.SYSTEMD_SYSTEM_HTTPD_IPA_CONF,
paths.SYSTEMD_SSSD_SERVICE,
paths.SYSTEMD_CERTMONGER_SERVICE,
paths.SYSTEMD_PKI_TOMCAT_SERVICE,
paths.SVC_LIST_FILE,
2014-10-20 11:03:33 +02:00
paths.OPENDNSSEC_CONF_FILE,
paths.OPENDNSSEC_KASP_FILE,
paths.OPENDNSSEC_ZONELIST_FILE,
paths.OPENDNSSEC_KASP_DB,
2014-10-20 11:03:33 +02:00
paths.DNSSEC_SOFTHSM2_CONF,
paths.DNSSEC_SOFTHSM_PIN_SO,
paths.IPA_ODS_EXPORTER_KEYTAB,
paths.IPA_DNSKEYSYNCD_KEYTAB,
2017-11-08 15:15:30 +01:00
paths.IPA_CUSTODIA_KEYS,
paths.IPA_CUSTODIA_CONF,
paths.GSSPROXY_CONF,
2015-09-01 16:24:44 +02:00
paths.HOSTS,
) + tuple(
2016-02-22 15:05:35 +01:00
os.path.join(paths.IPA_NSSDB_DIR, file)
2017-11-08 12:10:54 +01:00
for file in (certdb.NSS_DBM_FILES + certdb.NSS_SQL_FILES)
2013-03-13 09:36:41 -04:00
)
logs=(
paths.VAR_LOG_PKI_DIR,
paths.VAR_LOG_HTTPD_DIR,
paths.IPASERVER_INSTALL_LOG,
paths.KADMIND_LOG,
paths.MESSAGES,
paths.IPACLIENT_INSTALL_LOG,
paths.LOG_SECURE,
paths.IPASERVER_UNINSTALL_LOG,
paths.IPACLIENT_UNINSTALL_LOG,
paths.NAMED_RUN,
2013-03-13 09:36:41 -04:00
)
required_dirs=(
paths.TOMCAT_TOPLEVEL_DIR,
paths.TOMCAT_CA_DIR,
paths.TOMCAT_SIGNEDAUDIT_DIR,
paths.TOMCAT_CA_ARCHIVE_DIR,
paths.TOMCAT_KRA_DIR,
paths.TOMCAT_KRA_SIGNEDAUDIT_DIR,
paths.TOMCAT_KRA_ARCHIVE_DIR,
)
2013-03-13 09:36:41 -04:00
def __init__(self, options, args):
super(Backup, self).__init__(options, args)
self._conn = None
self.files = list(self.files)
self.dirs = list(self.dirs)
self.logs = list(self.logs)
@classmethod
def add_options(cls, parser):
super(Backup, cls).add_options(parser, debug_option=True)
2018-05-23 12:33:01 +02:00
parser.add_option(
"--gpg-keyring", dest="gpg_keyring",
help=optparse.SUPPRESS_HELP)
parser.add_option(
"--gpg", dest="gpg", action="store_true",
default=False, help="Encrypt the backup")
parser.add_option(
"--data", dest="data_only", action="store_true",
2013-03-13 09:36:41 -04:00
default=False, help="Backup only the data")
2018-05-23 12:33:01 +02:00
parser.add_option(
"--logs", dest="logs", action="store_true",
2013-03-13 09:36:41 -04:00
default=False, help="Include log files in backup")
2018-05-23 12:33:01 +02:00
parser.add_option(
"--online", dest="online", action="store_true",
default=False,
help="Perform the LDAP backups online, for data only.")
2013-03-13 09:36:41 -04:00
def setup_logging(self, log_file_mode='a'):
super(Backup, self).setup_logging(log_file_mode='a')
def validate_options(self):
options = self.options
super(Backup, self).validate_options(needs_root=True)
installutils.check_server_configuration()
if options.gpg_keyring is not None:
2018-05-23 12:33:01 +02:00
print(
"--gpg-keyring is no longer supported, use GNUPGHOME "
"environment variable to use a custom GnuPG2 directory.",
file=sys.stderr
)
2013-03-13 09:36:41 -04:00
options.gpg = True
if options.online and not options.data_only:
self.option_parser.error("You cannot specify --online "
"without --data")
if options.gpg:
tmpfd = write_tmp_file('encryptme')
2018-05-23 12:33:01 +02:00
newfile = encrypt_file(tmpfd.name, False)
2013-03-13 09:36:41 -04:00
os.unlink(newfile)
if options.data_only and options.logs:
self.option_parser.error("You cannot specify --data "
"with --logs")
def run(self):
options = self.options
super(Backup, self).run()
api.bootstrap(in_server=True, context='backup', confdir=paths.ETC_IPA)
2013-03-13 09:36:41 -04:00
api.finalize()
2017-05-23 18:35:57 +02:00
logger.info("Preparing backup on %s", api.env.host)
2013-03-13 09:36:41 -04:00
pent = pwd.getpwnam(constants.DS_USER)
2013-03-13 09:36:41 -04:00
self.top_dir = tempfile.mkdtemp("ipa")
os.chown(self.top_dir, pent.pw_uid, pent.pw_gid)
2015-07-15 16:38:06 +02:00
os.chmod(self.top_dir, 0o750)
2013-03-13 09:36:41 -04:00
self.dir = os.path.join(self.top_dir, "ipa")
os.mkdir(self.dir)
os.chmod(self.dir, 0o750)
2013-03-13 09:36:41 -04:00
os.chown(self.dir, pent.pw_uid, pent.pw_gid)
self.header = os.path.join(self.top_dir, 'header')
cwd = os.getcwd()
try:
dirsrv = services.knownservices.dirsrv
2013-03-13 09:36:41 -04:00
self.add_instance_specific_data()
# We need the dirsrv running to get the list of services
dirsrv.start(capture_output=False)
self.get_connection()
self.create_header(options.data_only)
if options.data_only:
if not options.online:
2017-05-23 18:35:57 +02:00
logger.info('Stopping Directory Server')
2013-03-13 09:36:41 -04:00
dirsrv.stop(capture_output=False)
else:
2017-05-23 18:35:57 +02:00
logger.info('Stopping IPA services')
run([paths.IPACTL, 'stop'])
2013-03-13 09:36:41 -04:00
2015-11-09 18:28:47 +01:00
instance = installutils.realm_to_serverid(api.env.realm)
if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE %
instance):
if os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE %
(instance, 'ipaca')):
self.db2ldif(instance, 'ipaca', online=options.online)
self.db2ldif(instance, 'userRoot', online=options.online)
self.db2bak(instance, online=options.online)
2013-03-13 09:36:41 -04:00
if not options.data_only:
# create backup of auth configuration
auth_backup_path = os.path.join(paths.VAR_LIB_IPA, 'auth_backup')
tasks.backup_auth_configuration(auth_backup_path)
2013-03-13 09:36:41 -04:00
self.file_backup(options)
self.finalize_backup(options.data_only, options.gpg, options.gpg_keyring)
if options.data_only:
if not options.online:
2017-05-23 18:35:57 +02:00
logger.info('Starting Directory Server')
2013-03-13 09:36:41 -04:00
dirsrv.start(capture_output=False)
else:
2017-05-23 18:35:57 +02:00
logger.info('Starting IPA service')
run([paths.IPACTL, 'start'])
2013-03-13 09:36:41 -04:00
finally:
try:
os.chdir(cwd)
2015-07-30 16:49:29 +02:00
except Exception as e:
2017-05-23 18:35:57 +02:00
logger.error('Cannot change directory to %s: %s', cwd, e)
2013-03-13 09:36:41 -04:00
shutil.rmtree(self.top_dir)
def add_instance_specific_data(self):
'''
Add instance-specific files and directories.
2015-11-09 18:28:47 +01:00
NOTE: this adds some things that may not get backed up.
2013-03-13 09:36:41 -04:00
'''
serverid = installutils.realm_to_serverid(api.env.realm)
2015-11-09 18:28:47 +01:00
for dir in [paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % serverid,
paths.VAR_LIB_DIRSRV_INSTANCE_SCRIPTS_TEMPLATE % serverid,
paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % serverid]:
2013-03-13 09:36:41 -04:00
if os.path.exists(dir):
self.dirs.append(dir)
for file in (
paths.SYSCONFIG_DIRSRV_INSTANCE % serverid,
paths.ETC_TMPFILESD_DIRSRV % serverid,
):
if os.path.exists(file):
self.files.append(file)
2013-03-13 09:36:41 -04:00
self.files.append(
paths.HTTPD_PASSWD_FILE_FMT.format(host=api.env.host)
)
2015-11-09 18:28:47 +01:00
self.logs.append(paths.VAR_LOG_DIRSRV_INSTANCE_TEMPLATE % serverid)
2013-03-13 09:36:41 -04:00
def get_connection(self):
'''
Create an ldapi connection and bind to it using autobind as root.
'''
if self._conn is not None:
return self._conn
2016-11-01 14:52:33 +01:00
ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=api.env.realm)
self._conn = ipaldap.LDAPClient(ldap_uri)
2013-03-13 09:36:41 -04:00
try:
self._conn.external_bind()
2015-07-30 16:49:29 +02:00
except Exception as e:
2017-05-23 18:35:57 +02:00
logger.error("Unable to bind to LDAP server %s: %s",
self._conn.host, e)
2013-03-13 09:36:41 -04:00
return self._conn
def db2ldif(self, instance, backend, online=True):
'''
Create a LDIF backup of the data in this instance.
If executed online create a task and wait for it to complete.
For SELinux reasons this writes out to the 389-ds backup location
and we move it.
'''
2017-05-23 18:35:57 +02:00
logger.info('Backing up %s in %s to LDIF', backend, instance)
2013-03-13 09:36:41 -04:00
cn = time.strftime('export_%Y_%m_%d_%H_%M_%S')
dn = DN(('cn', cn), ('cn', 'export'), ('cn', 'tasks'), ('cn', 'config'))
ldifname = '%s-%s.ldif' % (instance, backend)
ldiffile = os.path.join(
paths.SLAPD_INSTANCE_LDIF_DIR_TEMPLATE % instance,
2013-03-13 09:36:41 -04:00
ldifname)
if online:
conn = self.get_connection()
ent = conn.make_entry(
dn,
{
'objectClass': ['top', 'extensibleObject'],
'cn': [cn],
'nsInstance': [backend],
'nsFilename': [ldiffile],
'nsUseOneFile': ['true'],
'nsExportReplica': ['true'],
}
)
try:
conn.add_entry(ent)
2015-07-30 16:49:29 +02:00
except Exception as e:
2013-03-13 09:36:41 -04:00
raise admintool.ScriptError('Unable to add LDIF task: %s'
% e)
2017-05-23 18:35:57 +02:00
logger.info("Waiting for LDIF to finish")
2013-03-13 09:36:41 -04:00
wait_for_task(conn, dn)
else:
2015-04-01 11:27:36 -04:00
args = [paths.DB2LDIF,
'-Z', instance,
2013-03-13 09:36:41 -04:00
'-r',
'-n', backend,
'-a', ldiffile]
2015-11-25 17:17:18 +01:00
result = run(args, raiseonerr=False)
if result.returncode != 0:
2017-05-23 18:35:57 +02:00
logger.critical('db2ldif failed: %s', result.error_log)
2013-03-13 09:36:41 -04:00
# Move the LDIF backup to our location
shutil.move(ldiffile, os.path.join(self.dir, ldifname))
def db2bak(self, instance, online=True):
'''
Create a BAK backup of the data and changelog in this instance.
If executed online create a task and wait for it to complete.
'''
2017-05-23 18:35:57 +02:00
logger.info('Backing up %s', instance)
2013-03-13 09:36:41 -04:00
cn = time.strftime('backup_%Y_%m_%d_%H_%M_%S')
dn = DN(('cn', cn), ('cn', 'backup'), ('cn', 'tasks'), ('cn', 'config'))
bakdir = os.path.join(paths.SLAPD_INSTANCE_BACKUP_DIR_TEMPLATE % (instance, instance))
2013-03-13 09:36:41 -04:00
if online:
conn = self.get_connection()
ent = conn.make_entry(
dn,
{
'objectClass': ['top', 'extensibleObject'],
'cn': [cn],
'nsInstance': ['userRoot'],
'nsArchiveDir': [bakdir],
'nsDatabaseType': ['ldbm database'],
}
)
try:
conn.add_entry(ent)
2015-07-30 16:49:29 +02:00
except Exception as e:
2013-03-13 09:36:41 -04:00
raise admintool.ScriptError('Unable to to add backup task: %s'
% e)
2017-05-23 18:35:57 +02:00
logger.info("Waiting for BAK to finish")
2013-03-13 09:36:41 -04:00
wait_for_task(conn, dn)
else:
2015-04-01 11:27:36 -04:00
args = [paths.DB2BAK, bakdir, '-Z', instance]
2015-11-25 17:17:18 +01:00
result = run(args, raiseonerr=False)
if result.returncode != 0:
2017-05-23 18:35:57 +02:00
logger.critical('db2bak failed: %s', result.error_log)
2013-03-13 09:36:41 -04:00
shutil.move(bakdir, self.dir)
def file_backup(self, options):
def verify_directories(dirs):
return [s for s in dirs if os.path.exists(s)]
tarfile = os.path.join(self.dir, 'files.tar')
2017-05-23 18:35:57 +02:00
logger.info("Backing up files")
2013-03-13 09:36:41 -04:00
args = ['tar',
2014-05-28 17:16:04 -06:00
'--exclude=/var/lib/ipa/backup',
2013-03-13 09:36:41 -04:00
'--xattrs',
'--selinux',
'-cf',
tarfile
2013-03-13 09:36:41 -04:00
]
args.extend(verify_directories(self.dirs))
args.extend(verify_directories(self.files))
if options.logs:
args.extend(verify_directories(self.logs))
2015-11-25 17:17:18 +01:00
result = run(args, raiseonerr=False)
if result.returncode != 0:
raise admintool.ScriptError('tar returned non-zero code %d: %s' %
(result.returncode, result.error_log))
# Backup the necessary directory structure. This is a separate
# call since we are using the '--no-recursion' flag to store
# the directory structure only, no files.
missing_directories = verify_directories(self.required_dirs)
if missing_directories:
args = ['tar',
'--exclude=/var/lib/ipa/backup',
'--xattrs',
'--selinux',
'--no-recursion',
'-rf', # -r appends to an existing archive
tarfile,
]
args.extend(missing_directories)
2015-11-25 17:17:18 +01:00
result = run(args, raiseonerr=False)
if result.returncode != 0:
raise admintool.ScriptError(
'tar returned non-zero code %d '
'when adding directory structure: %s' %
(result.returncode, result.error_log))
# Compress the archive. This is done separately, since 'tar' cannot
# append to a compressed archive.
result = run([paths.GZIP, tarfile], raiseonerr=False)
2015-11-25 17:17:18 +01:00
if result.returncode != 0:
raise admintool.ScriptError(
'gzip returned non-zero code %d '
'when compressing the backup: %s' %
(result.returncode, result.error_log))
# Rename the archive back to files.tar to preserve compatibility
os.rename(os.path.join(self.dir, 'files.tar.gz'), tarfile)
2013-03-13 09:36:41 -04:00
def create_header(self, data_only):
'''
Create the backup file header that contains the meta data about
this particular backup.
'''
config = SafeConfigParser()
config.add_section("ipa")
if data_only:
config.set('ipa', 'type', 'DATA')
else:
config.set('ipa', 'type', 'FULL')
config.set('ipa', 'time', time.strftime(ISO8601_DATETIME_FMT, time.gmtime()))
config.set('ipa', 'host', api.env.host)
config.set('ipa', 'ipa_version', str(version.VERSION))
config.set('ipa', 'version', '1')
dn = DN(('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
services_cns = []
try:
conn = self.get_connection()
services = conn.get_entries(dn, conn.SCOPE_ONELEVEL)
except errors.NetworkError:
2017-05-23 18:35:57 +02:00
logger.critical(
2013-03-13 09:36:41 -04:00
"Unable to obtain list of master services, continuing anyway")
2015-07-30 16:49:29 +02:00
except Exception as e:
2017-05-23 18:35:57 +02:00
logger.error("Failed to read services from '%s': %s",
conn.host, e)
2013-03-13 09:36:41 -04:00
else:
services_cns = [s.single_value['cn'] for s in services]
2013-03-13 09:36:41 -04:00
config.set('ipa', 'services', ','.join(services_cns))
with open(self.header, 'w') as fd:
config.write(fd)
def finalize_backup(self, data_only=False, encrypt=False, keyring=None):
'''
Create the final location of the backup files and move the files
we've backed up there, optionally encrypting them.
This is done in a couple of steps. We have a directory that
contains the tarball of the files, a directory that contains
the db2bak output and an LDIF.
These, along with the header, are moved into a new subdirectory
in /var/lib/ipa/backup.
'''
if data_only:
2014-10-03 17:27:57 -06:00
backup_dir = os.path.join(paths.IPA_BACKUP_DIR, time.strftime('ipa-data-%Y-%m-%d-%H-%M-%S'))
2013-03-13 09:36:41 -04:00
filename = os.path.join(backup_dir, "ipa-data.tar")
else:
2014-10-03 17:27:57 -06:00
backup_dir = os.path.join(paths.IPA_BACKUP_DIR, time.strftime('ipa-full-%Y-%m-%d-%H-%M-%S'))
2013-03-13 09:36:41 -04:00
filename = os.path.join(backup_dir, "ipa-full.tar")
os.mkdir(backup_dir)
os.chmod(backup_dir, 0o700)
2013-03-13 09:36:41 -04:00
os.chdir(self.dir)
args = ['tar',
'--xattrs',
'--selinux',
'-czf',
filename,
'.'
]
2015-11-25 17:17:18 +01:00
result = run(args, raiseonerr=False)
if result.returncode != 0:
raise admintool.ScriptError(
'tar returned non-zero code %s: %s' %
(result.returncode, result.error_log))
2013-03-13 09:36:41 -04:00
if encrypt:
2017-05-23 18:35:57 +02:00
logger.info('Encrypting %s', filename)
2018-05-23 12:33:01 +02:00
filename = encrypt_file(filename)
2013-03-13 09:36:41 -04:00
shutil.move(self.header, backup_dir)
2017-05-23 18:35:57 +02:00
logger.info('Backed up to %s', backup_dir)