Add python script to dynamically compose releases
Currently, we do this in a combination of bash in this repo and the release files themselves. However, as we begin to support more different upgrade scenarios, this has proven to be difficult to maintain. Instead, we will use this python script to create a dictionary of releases which describes which release will be used at each point in the deploy: undercloud_install, undercloud_upgrade, overcloud_deploy, and overcloud_upgrade. This commit only provides an intial skeleton to work from. Follow-up commits will provide: 1. The ability to get a DLRN hash for each of the above breakpoints 2. A CLI for the tool so it can be called from the TOCI scripts 3. The ability to parse a featureset config for upgrade variables 4. The ability to output the dictionary for consumption by TOCI scripts Change-Id: Ibf61d7d12230f6714eb7dad91169aa043f5f8417
This commit is contained in:
parent
3801382fe5
commit
d0bb823d0c
|
@ -10,3 +10,13 @@ scripts/website/tripleo-docs/
|
|||
scripts/website/tripleosphinx/
|
||||
scripts/website/planet-2.0/
|
||||
scripts/website/planet.html.tmplc
|
||||
|
||||
.tox/
|
||||
.coverage
|
||||
.pytest_cache/
|
||||
__pycache__/
|
||||
scripts/emit_releases_file/assets/
|
||||
*.pyc
|
||||
scripts/emit_releases_file/htmlcov/
|
||||
scripts/emit_releases_file/pytest-report.html
|
||||
tripleo_ci.egg-info/
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
import logging
|
||||
|
||||
RELEASES = ['newton', 'ocata', 'pike', 'queens', 'master']
|
||||
LONG_TERM_SUPPORT_RELEASES = ['queens']
|
||||
|
||||
|
||||
def get_relative_release(release, relative_idx):
|
||||
current_idx = RELEASES.index(release)
|
||||
absolute_idx = current_idx + relative_idx
|
||||
return RELEASES[absolute_idx]
|
||||
|
||||
|
||||
def compose_releases_dictionary(stable_release, featureset):
|
||||
|
||||
if stable_release not in RELEASES:
|
||||
raise RuntimeError("The {} release is not supported by this tool"
|
||||
"Supported releases: {}".format(
|
||||
stable_release, RELEASES))
|
||||
|
||||
if (featureset.get('overcloud_upgrade') or
|
||||
featureset.get('undercloud_upgrade')) and \
|
||||
stable_release == RELEASES[0]:
|
||||
raise RuntimeError("Cannot upgrade to {}".format(RELEASES[0]))
|
||||
|
||||
if featureset.get('overcloud_upgrade') and \
|
||||
featureset.get('undercloud_upgrade'):
|
||||
raise RuntimeError("This tool currently only supports upgrading the "
|
||||
"undercloud OR the overcloud NOT both.")
|
||||
|
||||
if (featureset.get('overcloud_upgrade') or
|
||||
featureset.get('ffu_overcloud_upgrade')) and \
|
||||
not featureset.get('mixed_upgrade'):
|
||||
raise RuntimeError("Overcloud upgrade has to be mixed upgrades")
|
||||
|
||||
if featureset.get('ffu_overcloud_upgrade') and \
|
||||
stable_release not in LONG_TERM_SUPPORT_RELEASES:
|
||||
raise RuntimeError(
|
||||
"{} is not a long-term support release, and cannot be "
|
||||
"used in a fast forward upgrade. Current long-term support "
|
||||
"releases: {}".format(stable_release, LONG_TERM_SUPPORT_RELEASES))
|
||||
|
||||
releases_dictionary = {
|
||||
'undercloud_install_release': stable_release,
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': stable_release,
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': stable_release,
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': stable_release,
|
||||
'overcloud_target_hash': 'current-tripleo'
|
||||
}
|
||||
|
||||
if featureset.get('mixed_upgrade'):
|
||||
if featureset.get('overcloud_upgrade'):
|
||||
logging.info('Doing an overcloud upgrade')
|
||||
deploy_release = get_relative_release(stable_release, -1)
|
||||
releases_dictionary['overcloud_deploy_release'] = deploy_release
|
||||
|
||||
elif featureset.get('ffu_overcloud_upgrade'):
|
||||
logging.info('Doing an overcloud fast forward upgrade')
|
||||
deploy_release = get_relative_release(stable_release, -3)
|
||||
releases_dictionary['overcloud_deploy_release'] = deploy_release
|
||||
|
||||
elif featureset.get('undercloud_upgrade'):
|
||||
logging.info('Doing an undercloud upgrade')
|
||||
install_release = get_relative_release(stable_release, -1)
|
||||
releases_dictionary['undercloud_install_release'] = install_release
|
||||
|
||||
elif featureset.get('overcloud_update'):
|
||||
logging.info('Doing an overcloud update')
|
||||
releases_dictionary['overcloud_deploy_hash'] = \
|
||||
'previous-current-tripleo'
|
||||
|
||||
logging.debug("stable_release: %s, featureset: %s", stable_release,
|
||||
featureset)
|
||||
|
||||
logging.info('output releases: %s', releases_dictionary)
|
||||
|
||||
return releases_dictionary
|
||||
|
||||
|
||||
def shim_convert_old_release_names(releases_names):
|
||||
# TODO(trown): Remove this shim when we no longer need to use the
|
||||
# old style double release files.
|
||||
|
||||
oc_deploy_release = releases_names['overcloud_deploy_release']
|
||||
oc_target_release = releases_names['overcloud_target_release']
|
||||
uc_install_release = releases_names['undercloud_install_release']
|
||||
|
||||
if oc_deploy_release != oc_target_release:
|
||||
release_file = "undercloud-{}-overcloud-{}".format(
|
||||
uc_install_release, oc_deploy_release)
|
||||
releases_names['undercloud_install_release'] = release_file
|
||||
releases_names['undercloud_target_release'] = release_file
|
||||
releases_names['overcloud_deploy_release'] = release_file
|
||||
releases_names['overcloud_target_release'] = release_file
|
||||
|
||||
return releases_names
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# TODO read the feature set from a file path passed in the arguments
|
||||
featureset = {
|
||||
'mixed_upgrade': True,
|
||||
'overcloud_upgrade': True,
|
||||
}
|
||||
|
||||
# TODO read this from an argumment
|
||||
stable_release = 'queens'
|
||||
|
||||
releases_dictionary = compose_releases_dictionary(stable_release,
|
||||
featureset)
|
||||
|
||||
releases_dictionary = shim_convert_old_release_names(
|
||||
releases_dictionary)
|
|
@ -0,0 +1,2 @@
|
|||
[pytest]
|
||||
log_level = debug
|
|
@ -0,0 +1,76 @@
|
|||
from emit_releases_file import shim_convert_old_release_names
|
||||
|
||||
|
||||
def test_converting_from_oc_upgrade_has_double_release():
|
||||
releases_name = {
|
||||
'undercloud_install_release': 'master',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'master',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'queens',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'master',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}
|
||||
expected_releases_file = {
|
||||
'undercloud_install_release': 'undercloud-master-overcloud-queens',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'undercloud-master-overcloud-queens',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'undercloud-master-overcloud-queens',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'undercloud-master-overcloud-queens',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}
|
||||
assert (shim_convert_old_release_names(releases_name) ==
|
||||
expected_releases_file)
|
||||
|
||||
|
||||
def test_converting_from_uc_upgrade_has_single_release():
|
||||
releases_name = {
|
||||
'undercloud_install_release': 'queens',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'master',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'master',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'master',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}
|
||||
expected_releases_file = {
|
||||
'undercloud_install_release': 'queens',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'master',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'master',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'master',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}
|
||||
assert (shim_convert_old_release_names(releases_name) ==
|
||||
expected_releases_file)
|
||||
|
||||
|
||||
def test_converting_from_noop_has_single_release():
|
||||
releases_name = {
|
||||
'undercloud_install_release': 'master',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'master',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'master',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'master',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}
|
||||
expected_releases_file = {
|
||||
'undercloud_install_release': 'master',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'master',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'master',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'master',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}
|
||||
assert (shim_convert_old_release_names(releases_name) ==
|
||||
expected_releases_file)
|
|
@ -0,0 +1,158 @@
|
|||
from emit_releases_file import compose_releases_dictionary
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize('stable_release,expected_releases',
|
||||
[('master', {
|
||||
'undercloud_install_release': 'master',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'master',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'queens',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'master',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}), ('queens', {
|
||||
'undercloud_install_release': 'queens',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'queens',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'pike',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'queens',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}), ('pike', {
|
||||
'undercloud_install_release': 'pike',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'pike',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'ocata',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'pike',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
})])
|
||||
def test_overcloud_upgrade_is_n_minus_one_to_n(stable_release,
|
||||
expected_releases):
|
||||
featureset = {
|
||||
'mixed_upgrade': True,
|
||||
'overcloud_upgrade': True,
|
||||
}
|
||||
assert (compose_releases_dictionary(stable_release,
|
||||
featureset) == expected_releases)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('stable_release,expected_releases', [
|
||||
('queens', {
|
||||
'undercloud_install_release': 'queens',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'queens',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'newton',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'queens',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}),
|
||||
])
|
||||
def test_ffu_overcloud_upgrade_is_n_minus_three_to_n(stable_release,
|
||||
expected_releases):
|
||||
featureset = {
|
||||
'mixed_upgrade': True,
|
||||
'ffu_overcloud_upgrade': True,
|
||||
}
|
||||
assert (compose_releases_dictionary(stable_release,
|
||||
featureset) == expected_releases)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('stable_release,expected_releases', [
|
||||
('master', {
|
||||
'undercloud_install_release': 'queens',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'master',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'master',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'master',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}),
|
||||
])
|
||||
def test_undercloud_upgrade_is_n_minus_one_to_n(stable_release,
|
||||
expected_releases):
|
||||
featureset = {
|
||||
'undercloud_upgrade': True,
|
||||
}
|
||||
assert (compose_releases_dictionary(stable_release,
|
||||
featureset) == expected_releases)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'stable_release,expected_releases',
|
||||
[('master', {
|
||||
'undercloud_install_release': 'master',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'master',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'master',
|
||||
'overcloud_deploy_hash': 'previous-current-tripleo',
|
||||
'overcloud_target_release': 'master',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}), ('queens', {
|
||||
'undercloud_install_release': 'queens',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'queens',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'queens',
|
||||
'overcloud_deploy_hash': 'previous-current-tripleo',
|
||||
'overcloud_target_release': 'queens',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
})])
|
||||
def test_overcloud_update_target_is_hash(stable_release, expected_releases):
|
||||
featureset = {
|
||||
'overcloud_update': True,
|
||||
}
|
||||
assert (compose_releases_dictionary(stable_release,
|
||||
featureset) == expected_releases)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('stable_release,expected_releases',
|
||||
[('master', {
|
||||
'undercloud_install_release': 'master',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'master',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'master',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'master',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}), ('queens', {
|
||||
'undercloud_install_release': 'queens',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'queens',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'queens',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'queens',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}), ('pike', {
|
||||
'undercloud_install_release': 'pike',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'pike',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'pike',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'pike',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
}), ('ocata', {
|
||||
'undercloud_install_release': 'ocata',
|
||||
'undercloud_install_hash': 'current-tripleo',
|
||||
'undercloud_target_release': 'ocata',
|
||||
'undercloud_target_hash': 'current-tripleo',
|
||||
'overcloud_deploy_release': 'ocata',
|
||||
'overcloud_deploy_hash': 'current-tripleo',
|
||||
'overcloud_target_release': 'ocata',
|
||||
'overcloud_target_hash': 'current-tripleo',
|
||||
})])
|
||||
def test_noop_target_is_the_same(stable_release, expected_releases):
|
||||
featureset = {}
|
||||
assert (compose_releases_dictionary(stable_release,
|
||||
featureset) == expected_releases)
|
|
@ -0,0 +1,52 @@
|
|||
from emit_releases_file import compose_releases_dictionary
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize('featureset', [{
|
||||
'mixed_upgrade': True,
|
||||
'overcloud_upgrade': True
|
||||
}, {
|
||||
'undercloud_upgrade': True
|
||||
}])
|
||||
def test_upgrade_to_newton_is_unsupported(featureset):
|
||||
stable_release = 'newton'
|
||||
with pytest.raises(RuntimeError):
|
||||
compose_releases_dictionary(stable_release, featureset)
|
||||
|
||||
|
||||
def test_only_mixed_overcloud_upgrades_are_supported():
|
||||
featureset = {
|
||||
'overcloud_upgrade': True,
|
||||
'undercloud_upgrade': True,
|
||||
}
|
||||
|
||||
stable_release = 'queens'
|
||||
with pytest.raises(RuntimeError):
|
||||
compose_releases_dictionary(stable_release, featureset)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('upgrade_type',
|
||||
['ffu_overcloud_upgrade', 'overcloud_upgrade'])
|
||||
def test_overcloud_upgrades_has_to_be_mixed(upgrade_type):
|
||||
featureset = {
|
||||
upgrade_type: True,
|
||||
}
|
||||
stable_release = 'queens'
|
||||
with pytest.raises(RuntimeError):
|
||||
compose_releases_dictionary(stable_release, featureset)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('stable_release',
|
||||
['ocata', 'pike', 'newton', 'master'])
|
||||
def test_ffu_overcloud_upgrade_only_supported_from_newton(stable_release):
|
||||
featureset = {
|
||||
'mixed_upgrade': True,
|
||||
'ffu_overcloud_upgrade': True,
|
||||
}
|
||||
with pytest.raises(RuntimeError):
|
||||
compose_releases_dictionary(stable_release, featureset)
|
||||
|
||||
|
||||
def test_fail_with_wrong_release():
|
||||
with pytest.raises(RuntimeError):
|
||||
compose_releases_dictionary('foobar', {})
|
|
@ -1 +1,7 @@
|
|||
flake8
|
||||
pytest
|
||||
pytest-html
|
||||
pytest-cov
|
||||
mock
|
||||
requests
|
||||
pprint
|
||||
|
|
Loading…
Reference in New Issue