fuel-web/fuel_upgrade_system/fuel_upgrade/fuel_upgrade/upgrade.py
Evgeniy L 001ffbd156 Upgrades, remove saved version file on success
* created on_success method which upgrade
  script runs if upgrade succeed, don't
  fail upgrade in case of errors
* remove saved version files for all
  upgrades from working directories

It solves several problems:

1. user runs upgrade 5.0 -> 5.1 which fails
upgrade system saves version which we upgrade
from in file working_dir/5.1/version.yaml.
Then user runs upgrade 5.0 -> 5.0.1 which
successfully upgraded. Then user runs again
upgrade 5.0.1 -> 5.1, but there is saved file
working_dir/5.1/version.yaml which contains
5.0 version, and upgrade system thinks that
it's upgrading from 5.0 version, as result
it tries to make database dump from wrong
version of container.

2. without this hack user can run upgrade
second time and loose his data, this hack
prevents this case because before upgrade
checker will use current version instead
of saved version to determine version which
we run upgrade from.

Change-Id: I5e6ae6ba2ae2e60b9812e131d2a7c533f4a38ab6
Related-bug: #1349833
2014-07-31 16:48:56 +04:00

91 lines
3.0 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2014 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import logging
logger = logging.getLogger(__name__)
class UpgradeManager(object):
"""Upgrade manager is used to orchestrate upgrading process.
:param upgraders: a list with upgrader classes to use; each upgrader
must inherit the :class:`BaseUpgrader`
:param no_rollback: call :meth:`BaseUpgrader.rollback` method
in case of exception during execution
"""
def __init__(self, upgraders, no_rollback=True):
#: a list of upgraders to use
self._upgraders = upgraders
#: a list of used upgraders (needs by rollback feature)
self._used_upgraders = []
#: should we make rollback in case of error?
self._rollback = not no_rollback
def run(self):
"""Runs consequentially all registered upgraders.
.. note:: in case of exception the `rollback` method will be called
"""
logger.info('*** START UPGRADING')
for upgrader in self._upgraders:
try:
logger.debug('%s: upgrading...', upgrader.__class__.__name__)
self._used_upgraders.append(upgrader)
upgrader.upgrade()
except Exception as exc:
logger.exception(
'%s: failed to upgrade: "%s"',
upgrader.__class__.__name__, exc)
if self._rollback:
self.rollback()
logger.error('*** UPGRADE FAILED')
raise
self._on_success()
logger.info('*** UPGRADE DONE SUCCESSFULLY')
def _on_success(self):
"""Run on_success method for engines,
skip method call if there were some errors,
because if upgrade succeed we shouldn't
fail it.
"""
for upgrader in self._upgraders:
try:
logger.debug(
'%s: run on_success method',
upgrader.__class__.__name__)
upgrader.on_success()
except Exception as exc:
logger.exception(
'%s: skip the engine because failed to '
'execute on_success method: "%s"',
upgrader.__class__.__name__, exc)
def rollback(self):
logger.debug('Run rollback')
while self._used_upgraders:
upgrader = self._used_upgraders.pop()
logger.debug('%s: rollbacking...', upgrader.__class__.__name__)
upgrader.rollback()