278 lines
8.8 KiB
Python
Executable File
278 lines
8.8 KiB
Python
Executable File
# Copyright 2019 Canonical Ltd.
|
|
#
|
|
# 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.
|
|
|
|
"""Module for performing OpenStack upgrades.
|
|
|
|
This module contains a number of functions for upgrading OpenStack.
|
|
"""
|
|
import logging
|
|
import zaza.openstack.utilities.juju as juju_utils
|
|
|
|
import zaza.model
|
|
from zaza import sync_wrapper
|
|
from zaza.openstack.utilities.upgrade_utils import (
|
|
get_upgrade_groups,
|
|
)
|
|
|
|
|
|
async def async_pause_units(units, model_name=None):
|
|
"""Pause all units in unit list.
|
|
|
|
Pause all units in unit list. Wait for pause action
|
|
to complete.
|
|
|
|
:param units: List of unit names.
|
|
:type units: []
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
:rtype: juju.action.Action
|
|
:raises: zaza.model.ActionFailed
|
|
"""
|
|
logging.info("Pausing {}".format(', '.join(units)))
|
|
await zaza.model.async_run_action_on_units(
|
|
units,
|
|
'pause',
|
|
model_name=model_name,
|
|
raise_on_failure=True)
|
|
|
|
pause_units = sync_wrapper(async_pause_units)
|
|
|
|
|
|
async def async_resume_units(units, model_name=None):
|
|
"""Resume all units in unit list.
|
|
|
|
Resume all units in unit list. Wait for resume action
|
|
to complete.
|
|
|
|
:param units: List of unit names.
|
|
:type units: []
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
:rtype: juju.action.Action
|
|
:raises: zaza.model.ActionFailed
|
|
"""
|
|
logging.info("Resuming {}".format(', '.join(units)))
|
|
await zaza.model.async_run_action_on_units(
|
|
units,
|
|
'resume',
|
|
model_name=model_name,
|
|
raise_on_failure=True)
|
|
|
|
resume_units = sync_wrapper(async_resume_units)
|
|
|
|
|
|
async def async_action_unit_upgrade(units, model_name=None):
|
|
"""Run openstack-upgrade on all units in unit list.
|
|
|
|
Upgrade payload on all units in unit list. Wait for action
|
|
to complete.
|
|
|
|
:param units: List of unit names.
|
|
:type units: []
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
:rtype: juju.action.Action
|
|
:raises: zaza.model.ActionFailed
|
|
"""
|
|
logging.info("Upgrading {}".format(', '.join(units)))
|
|
await zaza.model.async_run_action_on_units(
|
|
units,
|
|
'openstack-upgrade',
|
|
model_name=model_name,
|
|
raise_on_failure=True)
|
|
|
|
action_unit_upgrade = sync_wrapper(async_action_unit_upgrade)
|
|
|
|
|
|
def action_upgrade_group(applications, model_name=None):
|
|
"""Upgrade units using action managed upgrades.
|
|
|
|
Upgrade all units of the given applications using action managed upgrades.
|
|
This involves the following process:
|
|
1) Take a unit from each application which has not been upgraded yet.
|
|
2) Pause all hacluster units assocaiated with units to be upgraded.
|
|
3) Pause target units.
|
|
4) Upgrade target units.
|
|
5) Resume target units.
|
|
6) Resume hacluster units paused in step 2.
|
|
7) Repeat until all units are upgraded.
|
|
|
|
:param applications: List of application names.
|
|
:type applications: []
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
"""
|
|
status = zaza.model.get_status(model_name=model_name)
|
|
done = []
|
|
while True:
|
|
target = []
|
|
for app in applications:
|
|
for unit in zaza.model.get_units(app, model_name=model_name):
|
|
if unit.entity_id not in done:
|
|
target.append(unit.entity_id)
|
|
break
|
|
else:
|
|
logging.info("All units of {} upgraded".format(app))
|
|
if not target:
|
|
break
|
|
hacluster_units = juju_utils.get_subordinate_units(
|
|
target,
|
|
'hacluster',
|
|
status=status,
|
|
model_name=model_name)
|
|
|
|
pause_units(hacluster_units, model_name=model_name)
|
|
pause_units(target, model_name=model_name)
|
|
|
|
action_unit_upgrade(target, model_name=model_name)
|
|
|
|
resume_units(target, model_name=model_name)
|
|
resume_units(hacluster_units, model_name=model_name)
|
|
|
|
done.extend(target)
|
|
|
|
|
|
def set_upgrade_application_config(applications, new_source,
|
|
action_managed=True, model_name=None):
|
|
"""Set the charm config for upgrade.
|
|
|
|
Set the charm config for upgrade.
|
|
|
|
:param applications: List of application names.
|
|
:type applications: []
|
|
:param new_source: New package origin.
|
|
:type new_source: str
|
|
:param action_managed: Whether to set action-managed-upgrade config option.
|
|
:type action_managed: bool
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
"""
|
|
for app in applications:
|
|
src_option = 'openstack-origin'
|
|
charm_options = zaza.model.get_application_config(
|
|
app, model_name=model_name)
|
|
try:
|
|
charm_options[src_option]
|
|
except KeyError:
|
|
src_option = 'source'
|
|
config = {
|
|
src_option: new_source}
|
|
if action_managed:
|
|
config['action-managed-upgrade'] = 'True'
|
|
logging.info("Setting config for {} to {}".format(app, config))
|
|
zaza.model.set_application_config(
|
|
app,
|
|
config,
|
|
model_name=model_name)
|
|
|
|
|
|
def is_action_upgradable(app, model_name=None):
|
|
"""Can application be upgraded using action managed upgrade method.
|
|
|
|
:param new_source: New package origin.
|
|
:type new_source: str
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
:returns: Whether app be upgraded using action managed upgrade method.
|
|
:rtype: bool
|
|
"""
|
|
config = zaza.model.get_application_config(app, model_name=model_name)
|
|
try:
|
|
config['action-managed-upgrade']
|
|
supported = True
|
|
except KeyError:
|
|
supported = False
|
|
return supported
|
|
|
|
|
|
def run_action_upgrade(group, new_source, model_name=None):
|
|
"""Upgrade payload of all applications in group using action upgrades.
|
|
|
|
:param group: List of applications to upgrade.
|
|
:type group
|
|
:param new_source: New package origin.
|
|
:type new_source: str
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
"""
|
|
set_upgrade_application_config(group, new_source, model_name=model_name)
|
|
action_upgrade_group(group, model_name=model_name)
|
|
|
|
|
|
def run_all_in_one_upgrade(group, new_source, model_name=None):
|
|
"""Upgrade payload of all applications in group using all-in-one method.
|
|
|
|
:param group: List of applications to upgrade.
|
|
:type group: []
|
|
:source: New package origin.
|
|
:type new_source: str
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
"""
|
|
set_upgrade_application_config(
|
|
group,
|
|
new_source,
|
|
model_name=model_name,
|
|
action_managed=False)
|
|
zaza.model.block_until_all_units_idle()
|
|
|
|
|
|
def run_upgrade(group, new_source, model_name=None):
|
|
"""Upgrade payload of all applications in group.
|
|
|
|
Upgrade apps using action managed upgrades where possible and fallback to
|
|
all_in_one method.
|
|
|
|
:param group: List of applications to upgrade.
|
|
:type group: []
|
|
:param new_source: New package origin.
|
|
:type new_source: str
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
"""
|
|
action_upgrade = []
|
|
all_in_one_upgrade = []
|
|
for app in group:
|
|
if is_action_upgradable(app, model_name=model_name):
|
|
action_upgrade.append(app)
|
|
else:
|
|
all_in_one_upgrade.append(app)
|
|
run_all_in_one_upgrade(
|
|
all_in_one_upgrade,
|
|
new_source,
|
|
model_name=model_name)
|
|
run_action_upgrade(
|
|
action_upgrade,
|
|
new_source,
|
|
model_name=model_name)
|
|
|
|
|
|
def run_upgrade_tests(new_source, model_name=None):
|
|
"""Upgrade payload of all applications in model.
|
|
|
|
This the most basic upgrade test. It should be adapted to add/remove
|
|
elements from the environment and add tests at intermediate stages.
|
|
|
|
:param new_source: New package origin.
|
|
:type new_source: str
|
|
:param model_name: Name of model to query.
|
|
:type model_name: str
|
|
"""
|
|
groups = get_upgrade_groups(model_name=model_name)
|
|
run_upgrade(groups['Core Identity'], new_source, model_name=model_name)
|
|
run_upgrade(groups['Storage'], new_source, model_name=model_name)
|
|
run_upgrade(groups['Control Plane'], new_source, model_name=model_name)
|
|
run_upgrade(groups['Compute'], new_source, model_name=model_name)
|
|
run_upgrade(groups['sweep_up'], new_source, model_name=model_name)
|