diff options
| author | Endi Sukma Dewata <edewata@redhat.com> | 2013-05-08 19:32:26 -0400 |
|---|---|---|
| committer | Endi Sukma Dewata <edewata@redhat.com> | 2013-05-15 15:47:27 -0400 |
| commit | aaf6e899f28ecfc5d75bc378a7dc6ccee5b2249e (patch) | |
| tree | a6c32a5edbc3f1a3c60ed995a9d0cf4d0e084fa9 /base/common/python | |
| parent | c90155c4983b55cc93b6d7cf131bd4aa541ab515 (diff) | |
| download | pki-aaf6e899f28ecfc5d75bc378a7dc6ccee5b2249e.tar.gz pki-aaf6e899f28ecfc5d75bc378a7dc6ccee5b2249e.tar.xz pki-aaf6e899f28ecfc5d75bc378a7dc6ccee5b2249e.zip | |
Added support for backup/restore on upgrade.
The upgrade framework has been modified to support backup and restore
functionality. A new method backup(filename) has been added to save
a file into a backup folder. The CLI's have been modified to accept
a --revert parameter which will restore the backup files one version
at a time.
Ticket #583
Diffstat (limited to 'base/common/python')
| -rw-r--r-- | base/common/python/pki/__init__.py | 7 | ||||
| -rw-r--r-- | base/common/python/pki/upgrade.py | 182 | ||||
| -rw-r--r-- | base/common/python/pki/util.py | 34 |
3 files changed, 204 insertions, 19 deletions
diff --git a/base/common/python/pki/__init__.py b/base/common/python/pki/__init__.py index 95f3a7335..404aa92d4 100644 --- a/base/common/python/pki/__init__.py +++ b/base/common/python/pki/__init__.py @@ -19,13 +19,14 @@ # All rights reserved. # -import re import os +import re CONF_DIR = '/etc/pki' SHARE_DIR = '/usr/share/pki' BASE_DIR = '/var/lib' +LOG_DIR = '/var/log/pki' PACKAGE_VERSION = SHARE_DIR + '/VERSION' @@ -137,6 +138,10 @@ class PropertyFile(object): self.lines.insert(index, line) + def remove_line(self, index): + + self.lines.pop(index) + def index(self, name): for i, line in enumerate(self.lines): diff --git a/base/common/python/pki/upgrade.py b/base/common/python/pki/upgrade.py index 3be5025b2..9f927130f 100644 --- a/base/common/python/pki/upgrade.py +++ b/base/common/python/pki/upgrade.py @@ -22,16 +22,18 @@ import functools import os import re +import shutil import traceback import pki +import pki.util DEFAULT_VERSION = '10.0.0' UPGRADE_DIR = pki.SHARE_DIR + '/upgrade' +BACKUP_DIR = pki.LOG_DIR + '/upgrade' SYSTEM_TRACKER = pki.CONF_DIR + '/pki.version' - verbose = False @@ -246,6 +248,9 @@ class PKIUpgradeScriptlet(object): self.message = None self.upgrader = None + def get_backup_dir(self): + return BACKUP_DIR + '/' + str(self.version) + '/' + str(self.index) + def can_upgrade(self): # A scriptlet can run if the version matches the tracker and @@ -276,6 +281,15 @@ class PKIUpgradeScriptlet(object): def upgrade(self): + backup_dir = self.get_backup_dir() + + if os.path.exists(backup_dir): + # remove old backup dir + shutil.rmtree(backup_dir) + + # create backup dir + os.makedirs(backup_dir) + try: if not self.can_upgrade(): if verbose: print 'Skipping system.' @@ -300,6 +314,58 @@ class PKIUpgradeScriptlet(object): raise pki.PKIException('Upgrade failed: ' + e.message, e) + def revert(self): + + backup_dir = self.get_backup_dir() + + if not os.path.exists(backup_dir): + return + + oldfiles = backup_dir + '/oldfiles' + if os.path.exists(oldfiles): + + # restore all backed up files + for root, dirnames, filenames in os.walk(oldfiles): + path = root[len(oldfiles):] + for filename in filenames: + source = root + '/' + filename + target = path + '/' + filename + + if verbose: print 'Restoring ' + target + pki.util.copyfile(source, target) + + newfiles = backup_dir + '/newfiles' + if os.path.exists(newfiles): + + # remove files that did not exist before upgrade + with open(newfiles, 'r') as f: + for filename in f: + filename = filename.strip('\n') + + if os.path.exists(filename): + if verbose: print 'Deleting ' + filename + os.remove(filename) + + def backup(self, filename): + + backup_dir = self.get_backup_dir() + backup_file = backup_dir + '/oldfiles' + filename + + if os.path.exists(filename): + + # if file exists, keep a copy + + if verbose: print 'Saving ' + filename + pki.util.copyfile(filename, backup_file) + + else: + + # otherwise, keep the name + + if verbose: print 'Recording ' + filename + with open(backup_dir + '/newfiles', 'a') as f: + f.write(filename + '\n') + def __eq__(self, other): return self.version == other.version and self.index == other.index @@ -330,30 +396,41 @@ class PKIUpgrader(object): return os.path.join(self.upgrade_dir, str(version)) - def versions(self): - - current_version = self.get_current_version() - target_version = self.get_target_version() + def all_versions(self): all_versions = [] if os.path.exists(self.upgrade_dir): for version in os.listdir(self.upgrade_dir): version = Version(version) - - # skip old versions - if version >= current_version: - all_versions.append(version) + all_versions.append(version) all_versions.sort() + return all_versions + + def versions(self): + + current_version = self.get_current_version() + target_version = self.get_target_version() + + current_versions = [] + + for version in self.all_versions(): + + # skip old versions + if version >= current_version: + current_versions.append(version) + + current_versions.sort() + versions = [] - for index, version in enumerate(all_versions): + for index, version in enumerate(current_versions): # link versions - if index < len(all_versions) - 1: - version.next = all_versions[index + 1] + if index < len(current_versions) - 1: + version.next = current_versions[index + 1] else: version.next = target_version @@ -367,10 +444,13 @@ class PKIUpgrader(object): def scriptlets(self, version): - version_dir = self.version_dir(version) - filenames = os.listdir(version_dir) scriptlets = [] + version_dir = self.version_dir(version) + if not os.path.exists(version_dir): + return scriptlets + + filenames = os.listdir(version_dir) for filename in filenames: # parse <index>-<classname> @@ -449,7 +529,7 @@ class PKIUpgrader(object): return # execute scriptlets - for index, scriptlet in enumerate(scriptlets): + for scriptlet in scriptlets: message = str(scriptlet.index) + '. ' + scriptlet.message @@ -493,7 +573,7 @@ class PKIUpgrader(object): versions = self.versions() - for index, version in enumerate(versions): + for version in versions: self.upgrade_version(version) print @@ -506,6 +586,72 @@ class PKIUpgrader(object): print 'Upgrade incomplete.' + def revert_version(self, version): + + print 'Reverting to version ' + str(version) + ':' + + scriptlets = self.scriptlets(version) + scriptlets.reverse() + + for scriptlet in scriptlets: + + message = str(scriptlet.index) + '. ' + scriptlet.message + + if self.silent: + print message + + else: + result = pki.read_text(message + ' (Yes/No)', + options=['Y', 'N'], default='Y', caseSensitive=False).lower() + + if result == 'n': + raise pki.PKIException('Revert canceled.') + + try: + scriptlet.revert() + + except pki.PKIException as e: + raise + + except Exception as e: + + print + + message = 'Revert failed: ' + e.message + + if verbose: + traceback.print_exc() + else: + print e.message + + print + + result = pki.read_text('Continue (Yes/No)', + options=['Y', 'N'], default='Y', delimiter='?', caseSensitive=False).lower() + + if result == 'n': + raise pki.PKIException(message, e) + + self.set_tracker(version) + + def revert(self): + + current_version = self.get_current_version() + + versions = self.all_versions() + versions.reverse() + + # find the first version smaller than the current version + for version in versions: + + if version >= current_version: + continue + + self.revert_version(version) + return + + print 'Unable to revert from version ' + str(current_version) + '.' + def show_tracker(self): tracker = self.get_tracker() @@ -527,13 +673,13 @@ class PKIUpgrader(object): tracker = self.get_tracker() tracker.set(version) + print 'Tracker has been set to version ' + str(version) + '.' + def reset_tracker(self): target_version = self.get_target_version() self.set_tracker(target_version) - print 'Tracker has been set to version ' + str(target_version) + '.' - def remove_tracker(self): tracker = self.get_tracker() diff --git a/base/common/python/pki/util.py b/base/common/python/pki/util.py new file mode 100644 index 000000000..7db4fbe79 --- /dev/null +++ b/base/common/python/pki/util.py @@ -0,0 +1,34 @@ +#!/usr/bin/python +# Authors: +# Endi S. Dewata <edewata@redhat.com> +# +# 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; version 2 of the License. +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2013 Red Hat, Inc. +# All rights reserved. +# + +import os +import shutil + + +def copyfile(source, dest): + + dir = os.path.dirname(dest) + if not os.path.exists(dir): + os.makedirs(dir) + + shutil.copy2(source, dest) + st = os.stat(source) + os.chown(dest, st.st_uid, st.st_gid) |
