From 9f049ca14403f3696d54d186e6b1b15181f055df Mon Sep 17 00:00:00 2001 From: Martin Basti Date: Fri, 10 Apr 2015 15:42:58 +0200 Subject: Server Upgrade: Verify version and platform Verify version and platform before upgrade or ipactl start|restart Upgrade: * do not allow upgrade on different platforms * do not allow upgrade data with higher version than build has Start: * do not start services if platform mismatch * do not start services if upgrade is needed * do not start services if data with higher version than build has New ipactl options: --skip-version-check: do not validate IPA version --ignore-service-failures (was --force): ignore if a service start fail and continue with starting other services --force: combine --skip-version-check and --ignore-service-failures https://fedorahosted.org/freeipa/ticket/4904 Reviewed-By: Jan Cholasta Reviewed-By: David Kupka --- ipaserver/install/dsinstance.py | 2 + ipaserver/install/installutils.py | 70 ++++++++++++++++++++++++++++++++- ipaserver/install/ipa_server_upgrade.py | 33 +++++++++++++++- 3 files changed, 103 insertions(+), 2 deletions(-) (limited to 'ipaserver/install') diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 8a76e773f..da00bcf82 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -511,6 +511,8 @@ class DsInstance(service.Service): sub_dict=self.sub_dict) files = ld.get_all_files(ldapupdate.UPDATES_DIR) ld.update(files) + installutils.store_version() + def __add_referint_module(self): self._ldap_mod("referint-conf.ldif") diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index 787a1207a..8a4f2cada 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -35,6 +35,8 @@ from dns.exception import DNSException import ldap from nss.error import NSPRError +import ipaplatform + from ipapython import ipautil, sysrestore, admintool, dogtag, version from ipapython.admintool import ScriptError from ipapython.ipa_log_manager import root_logger, log_mgr @@ -42,9 +44,10 @@ from ipalib.util import validate_hostname from ipapython import config from ipalib import errors, x509 from ipapython.dn import DN -from ipaserver.install import certs, service +from ipaserver.install import certs, service, sysupgrade from ipaplatform import services from ipaplatform.paths import paths +from ipaplatform.tasks import tasks # Used to determine install status IPA_MODULES = [ @@ -67,6 +70,27 @@ class HostReverseLookupError(HostLookupError): class HostnameLocalhost(HostLookupError): pass + +class UpgradeVersionError(Exception): + pass + + +class UpgradePlatformError(UpgradeVersionError): + pass + + +class UpgradeDataOlderVersionError(UpgradeVersionError): + pass + + +class UpgradeDataNewerVersionError(UpgradeVersionError): + pass + + +class UpgradeMissingVersionError(UpgradeVersionError): + pass + + class ReplicaConfig: def __init__(self, top_dir=None): self.realm_name = "" @@ -1037,3 +1061,47 @@ def load_external_cert(files, subject_base): ca_file.flush() return cert_file, ca_file + + +def store_version(): + """Store current data version and platform. This is required for check if + upgrade is required. + """ + sysupgrade.set_upgrade_state('ipa', 'data_version', + version.VENDOR_VERSION) + sysupgrade.set_upgrade_state('ipa', 'platform', ipaplatform.NAME) + + +def check_version(): + """ + :raise UpgradePlatformError: if platform is not the same + :raise UpgradeDataOlderVersionError: if data needs to be upgraded + :raise UpgradeDataNewerVersionError: older version of IPA was detected than data + :raise UpgradeMissingVersionError: if platform or version is missing + """ + platform = sysupgrade.get_upgrade_state('ipa', 'platform') + if platform is not None: + if platform != ipaplatform.NAME: + raise UpgradePlatformError( + "platform mismatch (expected '%s', current '%s')" % ( + platform, ipaplatform.NAME) + ) + else: + raise UpgradeMissingVersionError("no platform stored") + + data_version = sysupgrade.get_upgrade_state('ipa', 'data_version') + if data_version is not None: + parsed_data_ver = tasks.parse_ipa_version(data_version) + parsed_ipa_ver = tasks.parse_ipa_version(version.VENDOR_VERSION) + if parsed_data_ver < parsed_ipa_ver: + raise UpgradeDataOlderVersionError( + "data needs to be upgraded (expected version '%s', current " + "version '%s')" % (version.VENDOR_VERSION, data_version) + ) + elif parsed_data_ver > parsed_ipa_ver: + raise UpgradeDataNewerVersionError( + "data are in newer version than IPA (data version '%s', IPA " + "version '%s')" % (data_version, version.VENDOR_VERSION) + ) + else: + raise UpgradeMissingVersionError("no data_version stored") diff --git a/ipaserver/install/ipa_server_upgrade.py b/ipaserver/install/ipa_server_upgrade.py index 6d77fddc3..148d1fe7e 100644 --- a/ipaserver/install/ipa_server_upgrade.py +++ b/ipaserver/install/ipa_server_upgrade.py @@ -21,11 +21,21 @@ class ServerUpgrade(admintool.AdminTool): @classmethod def add_options(cls, parser): - super(ServerUpgrade, cls).add_options(parser, debug_option=True) + super(ServerUpgrade, cls).add_options(parser) + parser.add_option("--force", action="store_true", + dest="force", default=False, + help="force upgrade (alias for --skip-version-check)") + parser.add_option("--skip-version-check", action="store_true", + dest="skip_version_check", default=False, + help="skip version check. WARNING: this may break " + "your system") def validate_options(self): super(ServerUpgrade, self).validate_options(needs_root=True) + if self.options.force: + self.options.skip_version_check = True + try: installutils.check_server_configuration() except RuntimeError as e: @@ -43,6 +53,24 @@ class ServerUpgrade(admintool.AdminTool): options = self.options + if not options.skip_version_check: + # check IPA version and data version + try: + installutils.check_version() + except (installutils.UpgradePlatformError, + installutils.UpgradeDataNewerVersionError) as e: + raise admintool.ScriptError( + 'Unable to execute IPA upgrade: %s' % e, 1) + except installutils.UpgradeMissingVersionError as e: + self.log.info("Missing version: %s", e) + except installutils.UpgradeVersionError: + # Ignore other errors + pass + else: + self.log.info("Skipping version check") + self.log.warning("Upgrade without version check may break your " + "system") + realm = krbV.default_context().default_realm data_upgrade = IPAUpgrade(realm) data_upgrade.create_instance() @@ -57,6 +85,9 @@ class ServerUpgrade(admintool.AdminTool): else: self.log.info('Data update complete, no data were modified') + # store new data version after upgrade + installutils.store_version() + # FIXME: remove this when new installer will be ready # execute upgrade of configuration cmd = ['ipa-upgradeconfig', ] -- cgit