diff options
-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 | ||||
-rwxr-xr-x | base/common/sbin/pki-upgrade | 40 | ||||
-rw-r--r-- | base/server/python/pki/server/upgrade.py | 6 | ||||
-rwxr-xr-x | base/server/sbin/pki-server-upgrade | 41 | ||||
-rwxr-xr-x | base/server/upgrade/10.0.1/01-ReplaceRandomNumberGenerator | 10 | ||||
-rwxr-xr-x | base/server/upgrade/10.0.1/02-CloningInterfaceChanges | 2 | ||||
-rwxr-xr-x | base/server/upgrade/10.0.1/03-AddRestServlet | 2 | ||||
-rw-r--r-- | specs/pki-core.spec | 1 |
10 files changed, 279 insertions, 46 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) diff --git a/base/common/sbin/pki-upgrade b/base/common/sbin/pki-upgrade index 8b30f8fff..c739598d4 100755 --- a/base/common/sbin/pki-upgrade +++ b/base/common/sbin/pki-upgrade @@ -43,6 +43,7 @@ def usage(): print print ' --silent Upgrade in silent mode. Ignore any failures.' print ' --status Show upgrade status only. Do not perform upgrade.' + print ' --revert Revert the last version' print print ' -X Show advanced usage.' print ' -v, --verbose Run in verbose mode.' @@ -52,8 +53,9 @@ def usage(): def advancedUsage(): print 'WARNING: These options may render the system unusable.' print 'Usage: pki-upgrade [OPTIONS]' - print ' --remove-tracker Remove tracker' - print ' --reset-tracker Reset tracker to match package version' + print ' --remove-tracker Remove tracker' + print ' --reset-tracker Reset tracker to match package version' + print ' --set-tracker <version> Set tracker to a specific version' def main(argv): @@ -63,8 +65,8 @@ def main(argv): try: opts, args = getopt.getopt(argv[1:], 'hi:s:t:vX', [ 'scriptlet-version=', 'scriptlet-index=', - 'silent', 'status', - 'remove-tracker', 'reset-tracker', + 'silent', 'status', 'revert', + 'remove-tracker', 'reset-tracker', 'set-tracker=', 'verbose', 'help']) except getopt.GetoptError as e: @@ -72,20 +74,24 @@ def main(argv): usage() sys.exit(1) - version = None - index = None + scriptlet_version = None + scriptlet_index = None silent = False status = False + revert = False + remove_tracker = False reset_tracker = False + tracker_version = None + for o, a in opts: if o == '--scriptlet-version': - version = a + scriptlet_version = a elif o == '--scriptlet-index': - index = int(a) + scriptlet_index = int(a) elif o == '--silent': silent = True @@ -93,12 +99,18 @@ def main(argv): elif o == '--status': status = True + elif o == '--revert': + revert = True + elif o == '--remove-tracker': remove_tracker = True elif o == '--reset-tracker': reset_tracker = True + elif o == '--set-tracker': + tracker_version = pki.upgrade.Version(a) + elif o in ('-v', '--verbose'): pki.upgrade.verbose = True @@ -115,26 +127,32 @@ def main(argv): usage() sys.exit(1) - if index and not version: + if scriptlet_index and not scriptlet_version: print 'ERROR: --scriptlet-index requires --scriptlet-version' usage() sys.exit(1) try: upgrader = pki.upgrade.PKIUpgrader( - version = version, - index = index, + version = scriptlet_version, + index = scriptlet_index, silent = silent) if status: upgrader.status() + elif revert: + upgrader.revert() + elif remove_tracker: upgrader.remove_tracker() elif reset_tracker: upgrader.reset_tracker() + elif tracker_version is not None: + upgrader.set_tracker(tracker_version) + else: upgrader.upgrade() diff --git a/base/server/python/pki/server/upgrade.py b/base/server/python/pki/server/upgrade.py index 84e05127e..940dbe44a 100644 --- a/base/server/python/pki/server/upgrade.py +++ b/base/server/python/pki/server/upgrade.py @@ -29,6 +29,7 @@ import pki.server from pki.upgrade import verbose UPGRADE_DIR = pki.SHARE_DIR + '/server/upgrade' +BACKUP_DIR = pki.LOG_DIR + '/server/upgrade' INSTANCE_TRACKER = '%s/tomcat.conf' SUBSYSTEM_TRACKER = '%s/CS.cfg' @@ -40,6 +41,9 @@ class PKIServerUpgradeScriptlet(pki.upgrade.PKIUpgradeScriptlet): super(PKIServerUpgradeScriptlet, self).__init__() + def get_backup_dir(self): + return BACKUP_DIR + '/' + str(self.version) + '/' + str(self.index) + def can_upgrade(self, instance, subsystem=None): # A scriptlet can run if the version matches the tracker and @@ -293,6 +297,8 @@ class PKIServerUpgrader(pki.upgrade.PKIUpgrader): tracker = self.get_tracker(instance, subsystem) tracker.set(version) + print 'Tracker has been set to version ' + str(version) + '.' + def remove_tracker(self): for instance in self.instances(): diff --git a/base/server/sbin/pki-server-upgrade b/base/server/sbin/pki-server-upgrade index 58bc9ccb4..0b43f9b4b 100755 --- a/base/server/sbin/pki-server-upgrade +++ b/base/server/sbin/pki-server-upgrade @@ -24,6 +24,7 @@ import signal import sys import pki +import pki.upgrade import pki.server.upgrade @@ -47,6 +48,7 @@ def usage(): print print ' --silent Upgrade in silent mode. Ignore any failures.' print ' --status Show upgrade status only. Do not perform upgrade.' + print ' --revert Revert the last version' print print ' -X Show advanced usage.' print ' -v, --verbose Run in verbose mode.' @@ -56,8 +58,9 @@ def usage(): def advancedUsage(): print 'WARNING: These options may render the system unusable.' print 'Usage: pki-upgrade [OPTIONS]' - print ' --remove-tracker Remove tracker' - print ' --reset-tracker Reset tracker to match package version' + print ' --remove-tracker Remove tracker' + print ' --reset-tracker Reset tracker to match package version' + print ' --set-tracker <version> Set tracker to a specific version' def main(argv): @@ -68,8 +71,8 @@ def main(argv): opts, args = getopt.getopt(argv[1:], 'hi:s:t:vX', [ 'instance=', 'subsystem=', 'instance-type=', 'scriptlet-version=', 'scriptlet-index=', - 'silent', 'status', - 'remove-tracker', 'reset-tracker', + 'silent', 'status', 'revert', + 'remove-tracker', 'reset-tracker', 'set-tracker=', 'verbose', 'help']) except getopt.GetoptError as e: @@ -81,14 +84,18 @@ def main(argv): subsystemName = None instanceType = None - version = None - index = None + scriptlet_version = None + scriptlet_index = None silent = False status = False + revert = False + remove_tracker = False reset_tracker = False + tracker_version = None + for o, a in opts: if o in ('-i', '--instance'): instanceName = a @@ -100,10 +107,10 @@ def main(argv): instanceType = int(a) elif o == '--scriptlet-version': - version = a + scriptlet_version = a elif o == '--scriptlet-index': - index = int(a) + scriptlet_index = int(a) elif o == '--silent': silent = True @@ -111,12 +118,18 @@ def main(argv): elif o == '--status': status = True + elif o == '--revert': + revert = True + elif o == '--remove-tracker': remove_tracker = True elif o == '--reset-tracker': reset_tracker = True + elif o == '--set-tracker': + tracker_version = pki.upgrade.Version(a) + elif o in ('-v', '--verbose'): pki.upgrade.verbose = True @@ -138,7 +151,7 @@ def main(argv): usage() sys.exit(1) - if index and not version: + if scriptlet_index and not scriptlet_version: print 'ERROR: --scriptlet-index requires --scriptlet-version' usage() sys.exit(1) @@ -148,19 +161,25 @@ def main(argv): instanceName = instanceName, subsystemName = subsystemName, instanceType = instanceType, - version = version, - index = index, + version = scriptlet_version, + index = scriptlet_index, silent = silent) if status: upgrader.status() + elif revert: + upgrader.revert() + elif remove_tracker: upgrader.remove_tracker() elif reset_tracker: upgrader.reset_tracker() + elif tracker_version is not None: + upgrader.set_tracker(tracker_version) + else: upgrader.upgrade() diff --git a/base/server/upgrade/10.0.1/01-ReplaceRandomNumberGenerator b/base/server/upgrade/10.0.1/01-ReplaceRandomNumberGenerator index e73ede236..af3d53cc4 100755 --- a/base/server/upgrade/10.0.1/01-ReplaceRandomNumberGenerator +++ b/base/server/upgrade/10.0.1/01-ReplaceRandomNumberGenerator @@ -46,6 +46,8 @@ class ReplaceRandomNumberGenerator(pki.server.upgrade.PKIServerUpgradeScriptlet) 'webapps', subsystem.name, 'META-INF', 'context.xml') + self.backup(context_xml) + if not os.path.exists(context_xml): self.create_context_xml( instance, @@ -64,13 +66,11 @@ class ReplaceRandomNumberGenerator(pki.server.upgrade.PKIServerUpgradeScriptlet) with open(context_xml, 'w') as f: f.write(etree.tostring(document, pretty_print=True)) - def upgrade_instance(self, instance): self.update_root_context_xml(instance) self.update_pki_context_xml(instance) - def update_root_context_xml(self, instance): context_xml = os.path.join( @@ -78,6 +78,8 @@ class ReplaceRandomNumberGenerator(pki.server.upgrade.PKIServerUpgradeScriptlet) 'webapps', 'ROOT', 'META-INF', 'context.xml') + self.backup(context_xml) + if not os.path.exists(context_xml): self.create_context_xml(instance, 'server', 'ROOT') @@ -95,6 +97,8 @@ class ReplaceRandomNumberGenerator(pki.server.upgrade.PKIServerUpgradeScriptlet) 'webapps', 'pki', 'META-INF', 'context.xml') + self.backup(context_xml) + if not os.path.exists(context_xml): self.create_context_xml(instance, 'server', 'pki') @@ -105,7 +109,6 @@ class ReplaceRandomNumberGenerator(pki.server.upgrade.PKIServerUpgradeScriptlet) with open(context_xml, 'w') as f: f.write(etree.tostring(document, pretty_print=True)) - def create_context_xml(self, instance, pkg, context): uid = pwd.getpwnam('pkiuser').pw_uid @@ -147,7 +150,6 @@ class ReplaceRandomNumberGenerator(pki.server.upgrade.PKIServerUpgradeScriptlet) manager.set('secureRandomProvider', 'Mozilla-JSS') manager.set('secureRandomAlgorithm', 'pkcs11prng') - def update_authenticator(self, document): context = document.getroot() diff --git a/base/server/upgrade/10.0.1/02-CloningInterfaceChanges b/base/server/upgrade/10.0.1/02-CloningInterfaceChanges index d97cb4258..c70a4263c 100755 --- a/base/server/upgrade/10.0.1/02-CloningInterfaceChanges +++ b/base/server/upgrade/10.0.1/02-CloningInterfaceChanges @@ -106,6 +106,8 @@ class CloningInterfaceChanges(pki.server.upgrade.PKIServerUpgradeScriptlet): 'webapps', subsystem.name, 'WEB-INF', 'web.xml') + self.backup(web_xml) + self.doc = ET.parse(web_xml) self.root = self.doc.getroot() self.remove_get_token_info(subsystem.name) diff --git a/base/server/upgrade/10.0.1/03-AddRestServlet b/base/server/upgrade/10.0.1/03-AddRestServlet index dd656e972..37304e294 100755 --- a/base/server/upgrade/10.0.1/03-AddRestServlet +++ b/base/server/upgrade/10.0.1/03-AddRestServlet @@ -53,6 +53,8 @@ class AddRestServlet(pki.server.upgrade.PKIServerUpgradeScriptlet): 'webapps', subsystem.name, 'WEB-INF', 'web.xml') + self.backup(web_xml) + self.doc = ET.parse(web_xml) self.root = self.doc.getroot() self.add_rest_services_servlet() diff --git a/specs/pki-core.spec b/specs/pki-core.spec index 812f86b6f..158383b77 100644 --- a/specs/pki-core.spec +++ b/specs/pki-core.spec @@ -625,7 +625,6 @@ then else # On RPM upgrade run system upgrade echo "Upgrading system at `/bin/date`." >> /var/log/pki/pki-upgrade-%{version}.log 2>&1 - /sbin/pki-upgrade --remove-tracker >> /var/log/pki/pki-upgrade-%{version}.log 2>&1 /sbin/pki-upgrade --silent >> /var/log/pki/pki-upgrade-%{version}.log 2>&1 echo >> /var/log/pki/pki-upgrade-%{version}.log 2>&1 fi |