class BootstrapUpgrader(UpgradeEngine): """Bootstrap Upgrader. """ def __init__(self, *args, **kwargs): super(BootstrapUpgrader, self).__init__(*args, **kwargs) #: an action manager instance self._action_manager = ActionManager(self.config.bootstrap['actions']) def upgrade(self): logger.info('bootstrap upgrader: starting...') self._action_manager.do() logger.info('bootstrap upgrader: done') def rollback(self): logger.info('bootstrap upgrader: rollbacking...') self._action_manager.undo() logger.info('bootstrap upgrader: rollbacked') @property def required_free_space(self): return get_required_size_for_actions(self.config.bootstrap['actions'], self.config.update_path) def on_success(self): """Do nothing for this engine
class TargetImagesUpgrader(UpgradeEngine): """TargetImagesUpgrader. """ def __init__(self, *args, **kwargs): super(TargetImagesUpgrader, self).__init__(*args, **kwargs) #: an action manager instance self._action_manager = ActionManager( self.config.targetimages['actions']) def upgrade(self): logger.info('targetimages upgrader: starting...') self._action_manager.do() logger.info('targetimages upgrader: done') def rollback(self): logger.info('targetimages upgrader: rollbacking...') self._action_manager.undo() logger.info('targetimages upgrader: rollbacked') @property def required_free_space(self): return get_required_size_for_actions( self.config.targetimages['actions'], self.config.update_path) def on_success(self): """Do nothing for this engine
class BootstrapUpgrader(UpgradeEngine): """Bootstrap Upgrader. """ def __init__(self, *args, **kwargs): super(BootstrapUpgrader, self).__init__(*args, **kwargs) #: an action manager instance self._action_manager = ActionManager(self.config.bootstrap['actions']) def upgrade(self): logger.info('bootstrap upgrader: starting...') self._action_manager.do() logger.info('bootstrap upgrader: done') def rollback(self): logger.info('bootstrap upgrader: rollbacking...') self._action_manager.undo() logger.info('bootstrap upgrader: rollbacked') @property def required_free_space(self): return get_required_size_for_actions( self.config.bootstrap['actions'], self.config.update_path )
class OpenStackUpgrader(UpgradeEngine): """OpenStack Upgrader. The class is designed to do the following tasks: * install repos in the system * install manifests in the system * add new releases to nailgun's database * add notification about new releases """ def __init__(self, *args, **kwargs): super(OpenStackUpgrader, self).__init__(*args, **kwargs) #: a dictionary with meta information that could be used to #: format some data (paths, for example) self._meta = { 'version': self.config.new_version, 'master_ip': self.config.astute['ADMIN_NETWORK']['ipaddress'], } releases_yaml = self.config.openstack['releases'] with io.open(releases_yaml, 'r', encoding='utf-8') as f: #: an array with releases information self.releases = utils.load_fixture(f) #: a nailgun object - api wrapper self.nailgun = NailgunClient( self.config.endpoints['nailgun']['host'], self.config.endpoints['nailgun']['port'], ) self._update_conf() self._reset_state() #: an action manager that is used to install puppets/repos self.action_manager = ActionManager(self.config.openstack['actions']) def _update_conf(self): """Update some conf data: * convert relative paths to absolutes * format paths with metadata * format releases' orchestration data with metadata """ def fixpath(path): if not os.path.isabs(path): return os.path.join(self.update_path, path) return path # bulding valid repo paths for release in self.releases: if 'ubuntu' == release['operating_system'].lower(): repo = 'http://{master_ip}:8080/{version}/ubuntu/x86_64 ' \ 'precise main' else: repo = 'http://{master_ip}:8080/{version}/centos/x86_64' if 'orchestrator_data' not in release: release['orchestrator_data'] = { 'puppet_manifests_source': ('rsync://{master_ip}:/puppet/{version}/manifests/'), 'puppet_modules_source': ('rsync://{master_ip}:/puppet/{version}/modules/'), 'repo_metadata': { 'nailgun': repo, } } data = release['orchestrator_data'] data['repo_metadata']['nailgun'] = \ data['repo_metadata']['nailgun'].format(**self._meta) data['puppet_manifests_source'] = \ data['puppet_manifests_source'].format(**self._meta) data['puppet_modules_source'] = \ data['puppet_modules_source'].format(**self._meta) def upgrade(self): self._reset_state() logger.info('Starting upgrading...') self.action_manager.do() self.install_releases() logger.info('upgrade is done!') def rollback(self): logger.info('Starting rollbacking...') self.remove_releases() self.action_manager.undo() logger.info('rollback is done!') def on_success(self): """Do nothing for this engine """ def install_releases(self): # check releases for existing in nailgun side releases = self._get_unique_releases(self.releases, self.nailgun.get_releases()) # upload unexisting releases for release in releases: # register new release logger.debug('Register a new release: %s (%s)', release['name'], release['version']) response = self.nailgun.create_release(release) # save release id for futher possible rollback self._rollback_ids['release'].append(response['id']) # add notification abot successfull releases logger.debug('Add notification about new release: %s (%s)', release['name'], release['version']) response = self.nailgun.create_notification({ 'topic': 'done', 'message': 'New release available: {0} ({1})'.format( release['name'], release['version'], ), }) # save notification id for futher possible rollback self._rollback_ids['notification'].append(response['id']) def remove_releases(self): """Remove all releases that are created by current session. """ for release_id in reversed(self._rollback_ids['release']): try: logger.debug('Removing release with ID=%s', release_id) self.nailgun.remove_release(release_id) except (requests.exceptions.HTTPError) as exc: logger.exception(six.text_type(exc)) for notif_id in reversed(self._rollback_ids['notification']): try: logger.debug('Removing notification with ID=%s', notif_id) self.nailgun.remove_notification(notif_id) except (requests.exceptions.HTTPError) as exc: logger.exception(six.text_type(exc)) def _reset_state(self): """Remove rollback IDs from the arrays. """ #: a list of ids that have to be removed in case of rollback self._rollback_ids = { 'release': [], 'notification': [], } @classmethod def _get_unique_releases(cls, releases, existing_releases): """Returns a list of releases that aren't exist yet. :param releases: a list of releases to filter :param existing_releases: a list of existing releases :returns: a list of unique releases """ existing_releases = [(r['name'], r['version']) for r in existing_releases] unique = lambda r: (r['name'], r['version']) not in existing_releases return [r for r in releases if unique(r)] @property def required_free_space(self): return utils.get_required_size_for_actions( self.config.openstack['actions'], self.config.update_path)
class OpenStackUpgrader(UpgradeEngine): """OpenStack Upgrader. The class is designed to do the following tasks: * install repos in the system * install manifests in the system * add new releases to nailgun's database * add notification about new releases """ def __init__(self, *args, **kwargs): super(OpenStackUpgrader, self).__init__(*args, **kwargs) #: a dictionary with meta information that could be used to #: format some data (paths, for example) self._meta = { 'version': self.config.new_version, 'master_ip': self.config.astute['ADMIN_NETWORK']['ipaddress'], } releases_yaml = self.config.openstack['releases'] with io.open(releases_yaml, 'r', encoding='utf-8') as f: #: an array with releases information self.releases = utils.load_fixture(f) #: a nailgun object - api wrapper self.nailgun = NailgunClient( self.config.endpoints['nginx_nailgun']['host'], self.config.endpoints['nginx_nailgun']['port'], ) self._update_conf() self._reset_state() #: an action manager that is used to install puppets/repos self.action_manager = ActionManager(self.config.openstack['actions']) def _update_conf(self): """Update some conf data: * convert relative paths to absolutes * format paths with metadata * format releases' orchestration data with metadata """ def fixpath(path): if not os.path.isabs(path): return os.path.join(self.update_path, path) return path # bulding valid repo paths for release in self.releases: if 'ubuntu' == release['operating_system'].lower(): repo = 'http://{master_ip}:8080/{version}/ubuntu/x86_64 ' \ 'precise main' else: repo = 'http://{master_ip}:8080/{version}/centos/x86_64' if 'orchestrator_data' not in release: release['orchestrator_data'] = { 'puppet_manifests_source': ( 'rsync://{master_ip}:/puppet/{version}/manifests/'), 'puppet_modules_source': ( 'rsync://{master_ip}:/puppet/{version}/modules/'), 'repo_metadata': { 'nailgun': repo, } } data = release['orchestrator_data'] data['repo_metadata']['nailgun'] = \ data['repo_metadata']['nailgun'].format(**self._meta) data['puppet_manifests_source'] = \ data['puppet_manifests_source'].format(**self._meta) data['puppet_modules_source'] = \ data['puppet_modules_source'].format(**self._meta) def upgrade(self): self._reset_state() logger.info('Starting upgrading...') self.action_manager.do() self.install_releases() logger.info('upgrade is done!') def rollback(self): logger.info('Starting rollbacking...') self.remove_releases() self.action_manager.undo() logger.info('rollback is done!') def install_releases(self): # check releases for existing in nailgun side releases = self._get_unique_releases( self.releases, self.nailgun.get_releases()) # upload unexisting releases for release in releases: # register new release logger.debug('Register a new release: %s (%s)', release['name'], release['version']) response = self.nailgun.create_release(release) # save release id for futher possible rollback self._rollback_ids['release'].append(response['id']) # add notification abot successfull releases logger.debug('Add notification about new release: %s (%s)', release['name'], release['version']) response = self.nailgun.create_notification({ 'topic': 'release', 'message': 'New release available: {0} ({1})'.format( release['name'], release['version'], ), }) # save notification id for futher possible rollback self._rollback_ids['notification'].append(response['id']) def remove_releases(self): """Remove all releases that are created by current session. """ for release_id in reversed(self._rollback_ids['release']): try: logger.debug('Removing release with ID=%s', release_id) self.nailgun.remove_release(release_id) except ( requests.exceptions.HTTPError ) as exc: logger.exception(six.text_type(exc)) for notif_id in reversed(self._rollback_ids['notification']): try: logger.debug('Removing notification with ID=%s', notif_id) self.nailgun.remove_notification(notif_id) except ( requests.exceptions.HTTPError ) as exc: logger.exception(six.text_type(exc)) def _reset_state(self): """Remove rollback IDs from the arrays. """ #: a list of ids that have to be removed in case of rollback self._rollback_ids = { 'release': [], 'notification': [], } @classmethod def _get_unique_releases(cls, releases, existing_releases): """Returns a list of releases that aren't exist yet. :param releases: a list of releases to filter :param existing_releases: a list of existing releases :returns: a list of unique releases """ existing_releases = [ (r['name'], r['version']) for r in existing_releases ] unique = lambda r: (r['name'], r['version']) not in existing_releases return [r for r in releases if unique(r)] @property def required_free_space(self): return utils.get_required_size_for_actions( self.config.openstack['actions'], self.config.update_path )