def run(self): options = self.options super(Restore, self).run() self.backup_dir = self.args[0] if not os.path.isabs(self.backup_dir): self.backup_dir = os.path.join(paths.IPA_BACKUP_DIR, self.backup_dir) logger.info("Preparing restore from %s on %s", self.backup_dir, FQDN) self.header = os.path.join(self.backup_dir, 'header') try: self.read_header() except IOError as e: raise admintool.ScriptError("Cannot read backup metadata: %s" % e) if options.data_only: restore_type = 'DATA' else: restore_type = self.backup_type # These checks would normally be in the validate method but # we need to know the type of backup we're dealing with. if restore_type == 'FULL': if options.online: raise admintool.ScriptError( "File restoration cannot be done online") if options.instance or options.backend: raise admintool.ScriptError( "Restore must be in data-only mode when restoring a " "specific instance or backend") else: installutils.check_server_configuration() self.init_api() if options.instance: instance_dir = (paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % options.instance) if not os.path.exists(instance_dir): raise admintool.ScriptError( "Instance %s does not exist" % options.instance) self.instances = [options.instance] if options.backend: for instance in self.instances: db_dir = (paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % (instance, options.backend)) if os.path.exists(db_dir): break else: raise admintool.ScriptError( "Backend %s does not exist" % options.backend) self.backends = [options.backend] for instance, backend in itertools.product(self.instances, self.backends): db_dir = (paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % (instance, backend)) if os.path.exists(db_dir): break else: raise admintool.ScriptError( "Cannot restore a data backup into an empty system") logger.info("Performing %s restore from %s backup", restore_type, self.backup_type) if self.backup_host != FQDN: raise admintool.ScriptError( "Host name %s does not match backup name %s" % (FQDN, self.backup_host)) if self.backup_ipa_version != str(version.VERSION): logger.warning( "Restoring data from a different release of IPA.\n" "Data is version %s.\n" "Server is running %s.", self.backup_ipa_version, str(version.VERSION)) if (not options.unattended and not user_input("Continue to restore?", False)): raise admintool.ScriptError("Aborted") # Check have optional dependencies been installed for extra # features from backup if restore_type == 'FULL': if 'ADTRUST' in self.backup_services: if not adtrustinstance or not adtrustinstance.check_inst(): raise admintool.ScriptError( "Backup includes AD trust feature, it requires '{}' " "package. Please install the package and " "run ipa-restore again.".format( constants.IPA_ADTRUST_PACKAGE_NAME ) ) if 'DNS' in self.backup_services: if not os.path.isfile(paths.IPA_DNS_INSTALL): raise admintool.ScriptError( "Backup includes Integrated DNS feature, it requires " "'{}' package. Please install the package and " "run ipa-restore again.".format( constants.IPA_DNS_PACKAGE_NAME ) ) # Temporary directory for decrypting files before restoring self.top_dir = tempfile.mkdtemp("ipa") constants.DS_USER.chown(self.top_dir) os.chmod(self.top_dir, 0o750) self.dir = os.path.join(self.top_dir, "ipa") os.mkdir(self.dir) os.chmod(self.dir, 0o750) constants.DS_USER.chown(self.dir) logger.info("Temporary setting umask to 022") old_umask = os.umask(0o022) try: dirsrv = services.knownservices.dirsrv self.extract_backup() if restore_type == 'FULL': self.restore_default_conf() self.init_api(confdir=self.dir + paths.ETC_IPA) databases = [] for instance in self.instances: for backend in self.backends: database = (instance, backend) ldiffile = os.path.join(self.dir, '%s-%s.ldif' % database) if os.path.exists(ldiffile): databases.append(database) if options.instance: for instance, backend in databases: if instance == options.instance: break else: raise admintool.ScriptError( "Instance %s not found in backup" % options.instance) if options.backend: for instance, backend in databases: if backend == options.backend: break else: raise admintool.ScriptError( "Backend %s not found in backup" % options.backend) # Big fat warning if (not options.unattended and not user_input("Restoring data will overwrite existing live data. Continue to restore?", False)): raise admintool.ScriptError("Aborted") logger.info( "Each master will individually need to be re-initialized or") logger.info( "re-created from this one. The replication agreements on") logger.info( "masters running IPA 3.1 or earlier will need to be manually") logger.info( "re-enabled. See the man page for details.") logger.info("Disabling all replication.") self.disable_agreements() if restore_type != 'FULL': if not options.online: logger.info('Stopping Directory Server') dirsrv.stop(capture_output=False) else: logger.info('Starting Directory Server') dirsrv.start(capture_output=False) else: logger.info('Stopping IPA services') result = run([paths.IPACTL, 'stop'], raiseonerr=False) if result.returncode not in [0, 6]: logger.warning('Stopping IPA failed: %s', result.error_log) self.restore_selinux_booleans() http = httpinstance.HTTPInstance() # We do either a full file restore or we restore data. if restore_type == 'FULL': self.remove_old_files() self.clear_old_files() self.cert_restore_prepare() self.file_restore(options.no_logs) self.cert_restore() if 'CA' in self.backup_services: self.__create_dogtag_log_dirs() # Always restore the data from ldif # We need to restore both userRoot and ipaca. for instance, backend in databases: self.ldif2db(instance, backend, online=options.online) if restore_type != 'FULL': if not options.online: logger.info('Starting Directory Server') dirsrv.start(capture_output=False) else: # restore access controll configuration auth_backup_path = os.path.join(paths.VAR_LIB_IPA, 'auth_backup') if os.path.exists(auth_backup_path): tasks.restore_auth_configuration(auth_backup_path) # explicitly enable then disable the pki tomcatd service to # re-register its instance. FIXME, this is really wierd. services.knownservices.pki_tomcatd.enable() services.knownservices.pki_tomcatd.disable() logger.info('Restarting GSS-proxy') gssproxy = services.service('gssproxy', api) gssproxy.reload_or_restart() logger.info('Starting IPA services') run([paths.IPACTL, 'start']) logger.info('Restarting SSSD') sssd = services.service('sssd', api) sssd.restart() logger.info('Restarting oddjobd') oddjobd = services.service('oddjobd', api) if not oddjobd.is_enabled(): logger.info("Enabling oddjobd") oddjobd.enable() oddjobd.start() http.remove_httpd_ccaches() # have the daemons pick up their restored configs tasks.systemd_daemon_reload() # Restart IPA a final time. # Starting then restarting is necessary to make sure some # daemons like httpd are restarted # (https://pagure.io/freeipa/issue/8226). logger.info('Restarting IPA services') result = run([paths.IPACTL, 'restart'], raiseonerr=False) if result.returncode != 0: logger.error('Restarting IPA failed: %s', result.error_log) finally: shutil.rmtree(self.top_dir) logger.info("Restoring umask to %s", old_umask) os.umask(old_umask)
def check_for_installed_deps(): # Check if samba packages are installed if not adtrustinstance.check_inst(): raise ScriptError("Aborting installation.")