Change-Id: Iaaf8628a74f7d90a41cc7f0d58b2a2c49f9bf815
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane
2025-12-01 14:14:44 +00:00
parent 7bcf7d0878
commit d8dea5bafc
11 changed files with 133 additions and 106 deletions

View File

@@ -12,13 +12,15 @@ repos:
- id: debug-statements
- id: check-yaml
files: .*\.(yaml|yml)$
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.7
hooks:
- id: ruff-check
args: ['--fix', '--unsafe-fixes']
- id: ruff-format
- repo: https://opendev.org/openstack/hacking
rev: 7.0.0
rev: 8.0.0
hooks:
- id: hacking
additional_dependencies: []
- repo: https://github.com/asottile/pyupgrade
rev: v3.20.0
hooks:
- id: pyupgrade
args: [--py310-plus]
exclude: '^(doc|releasenotes)/.*$'

View File

@@ -34,10 +34,7 @@ copyright = '2018, Oslo Contributors'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
'openstackdocstheme'
]
extensions = ['sphinx.ext.autodoc', 'openstackdocstheme']
# The master toctree document.
master_doc = 'index'

View File

@@ -22,22 +22,19 @@ from oslo_upgradecheck import upgradecheck
class Checks(upgradecheck.UpgradeCommands):
def success(self):
return upgradecheck.Result(upgradecheck.Code.SUCCESS,
'Always succeeds')
return upgradecheck.Result(
upgradecheck.Code.SUCCESS, 'Always succeeds'
)
def failure(self):
return upgradecheck.Result(upgradecheck.Code.FAILURE, 'Always fails')
_upgrade_checks = (('always succeeds', success),
('always fails', failure),
)
_upgrade_checks = (('always succeeds', success), ('always fails', failure))
def main():
return upgradecheck.main(
conf=cfg.CONF,
project='myprojectname',
upgrade_command=Checks(),
conf=cfg.CONF, project='myprojectname', upgrade_command=Checks()
)

View File

@@ -26,16 +26,17 @@ def check_policy_json(self, conf):
# NOTE(gmann): This method need [oslo_policy].policy_file
# config value so register those options in case they
# are not register by services.
conf.register_opts(policy_opts._options,
group=policy_opts._option_group)
conf.register_opts(policy_opts._options, group=policy_opts._option_group)
msg = ("Your policy file is JSON-formatted which is "
"deprecated. You need to switch to YAML-formatted file. "
"Use the ``oslopolicy-convert-json-to-yaml`` "
"tool to convert the existing JSON-formatted files to "
"YAML in a backwards-compatible manner: "
"https://docs.openstack.org/oslo.policy/"
"latest/cli/oslopolicy-convert-json-to-yaml.html.")
msg = (
"Your policy file is JSON-formatted which is "
"deprecated. You need to switch to YAML-formatted file. "
"Use the ``oslopolicy-convert-json-to-yaml`` "
"tool to convert the existing JSON-formatted files to "
"YAML in a backwards-compatible manner: "
"https://docs.openstack.org/oslo.policy/"
"latest/cli/oslopolicy-convert-json-to-yaml.html."
)
status = upgradecheck.Result(upgradecheck.Code.SUCCESS)
# Check if policy file exist and is JSON-formatted.
policy_path = conf.find_file(conf.oslo_policy.policy_file)

View File

@@ -26,24 +26,24 @@ from oslo_upgradecheck import upgradecheck
class TestUpgradeCheckPolicyJSON(base.BaseTestCase):
def setUp(self):
super().setUp()
conf_fixture = self.useFixture(config.Config())
conf_fixture.load_raw_values()
self.conf = conf_fixture.conf
self.conf.register_opts(policy_opts._options,
group=policy_opts._option_group)
self.conf.register_opts(
policy_opts._options, group=policy_opts._option_group
)
self.cmd = upgradecheck.UpgradeCommands()
self.cmd._upgrade_checks = (('Policy File JSON to YAML Migration',
(common_checks.check_policy_json,
{'conf': self.conf})),)
self.cmd._upgrade_checks = (
(
'Policy File JSON to YAML Migration',
(common_checks.check_policy_json, {'conf': self.conf}),
),
)
self.data = {
'rule_admin': 'True',
'rule_admin2': 'is_admin:True'
}
self.data = {'rule_admin': 'True', 'rule_admin2': 'is_admin:True'}
self.temp_dir = self.useFixture(fixtures.TempDir())
fd, self.json_file = tempfile.mkstemp(dir=self.temp_dir.path)
fd, self.yaml_file = tempfile.mkstemp(dir=self.temp_dir.path)
@@ -59,44 +59,45 @@ class TestUpgradeCheckPolicyJSON(base.BaseTestCase):
return original_search_dirs(dirs, name)
mock_search_dir = self.useFixture(
fixtures.MockPatch('oslo_config.cfg._search_dirs')).mock
fixtures.MockPatch('oslo_config.cfg._search_dirs')
).mock
mock_search_dir.side_effect = fake_search_dirs
def test_policy_json_file_fail_upgrade(self):
# Test with policy json file full path set in config.
self.conf.set_override('policy_file', self.json_file,
group="oslo_policy")
self.assertEqual(upgradecheck.Code.FAILURE,
self.cmd.check())
self.conf.set_override(
'policy_file', self.json_file, group="oslo_policy"
)
self.assertEqual(upgradecheck.Code.FAILURE, self.cmd.check())
def test_policy_yaml_file_pass_upgrade(self):
# Test with full policy yaml file path set in config.
self.conf.set_override('policy_file', self.yaml_file,
group="oslo_policy")
self.assertEqual(upgradecheck.Code.SUCCESS,
self.cmd.check())
self.conf.set_override(
'policy_file', self.yaml_file, group="oslo_policy"
)
self.assertEqual(upgradecheck.Code.SUCCESS, self.cmd.check())
def test_no_policy_file_pass_upgrade(self):
# Test with no policy file exist, means use policy from code.
self.conf.set_override('policy_file', 'non_exist_file',
group="oslo_policy")
self.assertEqual(upgradecheck.Code.SUCCESS,
self.cmd.check())
self.conf.set_override(
'policy_file', 'non_exist_file', group="oslo_policy"
)
self.assertEqual(upgradecheck.Code.SUCCESS, self.cmd.check())
def test_default_policy_yaml_file_pass_upgrade(self):
self.conf.set_override('policy_file', 'policy.yaml',
group="oslo_policy")
self.conf.set_override(
'policy_file', 'policy.yaml', group="oslo_policy"
)
tmpfilename = os.path.join(self.temp_dir.path, 'policy.yaml')
with open(tmpfilename, 'w') as fh:
yaml.dump(self.data, fh)
self.assertEqual(upgradecheck.Code.SUCCESS,
self.cmd.check())
self.assertEqual(upgradecheck.Code.SUCCESS, self.cmd.check())
def test_old_default_policy_json_file_fail_upgrade(self):
self.conf.set_override('policy_file', 'policy.json',
group="oslo_policy")
self.conf.set_override(
'policy_file', 'policy.json', group="oslo_policy"
)
tmpfilename = os.path.join(self.temp_dir.path, 'policy.json')
with open(tmpfilename, 'w') as fh:
jsonutils.dump(self.data, fh)
self.assertEqual(upgradecheck.Code.FAILURE,
self.cmd.check())
self.assertEqual(upgradecheck.Code.FAILURE, self.cmd.check())

View File

@@ -29,7 +29,6 @@ from oslo_upgradecheck import upgradecheck
class TestUpgradeCheckResult(base.BaseTestCase):
def test_details(self):
result = upgradecheck.Result(upgradecheck.Code.SUCCESS, 'test details')
self.assertEqual(0, result.code)
@@ -38,8 +37,9 @@ class TestUpgradeCheckResult(base.BaseTestCase):
class TestCommands(upgradecheck.UpgradeCommands):
def success(self):
return upgradecheck.Result(upgradecheck.Code.SUCCESS,
'Always succeeds')
return upgradecheck.Result(
upgradecheck.Code.SUCCESS, 'Always succeeds'
)
def warning(self):
return upgradecheck.Result(upgradecheck.Code.WARNING, 'Always warns')
@@ -47,10 +47,11 @@ class TestCommands(upgradecheck.UpgradeCommands):
def failure(self):
return upgradecheck.Result(upgradecheck.Code.FAILURE, 'Always fails')
_upgrade_checks = (('always succeeds', success),
('always warns', warning),
('always fails', failure),
)
_upgrade_checks = (
('always succeeds', success),
('always warns', warning),
('always fails', failure),
)
class SuccessCommands(TestCommands):
@@ -98,10 +99,13 @@ class TestMain(base.BaseTestCase):
class TestExampleFile(base.BaseTestCase):
def test_example_main(self):
path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
'../../doc/source/main.py')
path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'../../doc/source/main.py',
)
# The example includes both a passing and failing test, which means the
# overall result is failure.
self.assertEqual(
upgradecheck.Code.FAILURE,
subprocess.call([sys.executable, path, 'upgrade', 'check']))
subprocess.call([sys.executable, path, 'upgrade', 'check']),
)

View File

@@ -77,14 +77,18 @@ class UpgradeCommands:
done through the sqlalchemy query language directly like the database
schema migrations.
"""
display_title = _('Upgrade Check Results')
_upgrade_checks = ()
def _get_details(self, upgrade_check_result):
if upgrade_check_result.details is not None:
# wrap the text on the details to 60 characters
return '\n'.join(textwrap.wrap(upgrade_check_result.details, 60,
subsequent_indent=' '))
return '\n'.join(
textwrap.wrap(
upgrade_check_result.details, 60, subsequent_indent=' '
)
)
def check(self):
"""Performs checks to see if the deployment is ready for upgrade.
@@ -125,17 +129,22 @@ class UpgradeCommands:
# Since registering opts can be overridden by consuming code, we can't
# assume that our locally defined option exists.
if (hasattr(CONF, 'command') and hasattr(CONF.command, 'json') and
CONF.command.json):
if (
hasattr(CONF, 'command')
and hasattr(CONF.command, 'json')
and CONF.command.json
):
# NOTE(bnemec): We use str on the translated string to
# force immediate translation if lazy translation is in use.
# See lp1801761 for details.
output = {'name': str(self.display_title), 'checks': []}
for name, result in check_results:
output['checks'].append(
{'check': name,
'result': result.code,
'details': result.details}
{
'check': name,
'result': result.code,
'details': result.details,
}
)
print(json.dumps(output))
else:
@@ -143,19 +152,17 @@ class UpgradeCommands:
# force immediate translation if lazy translation is in use.
# See lp1801761 for details.
t = prettytable.PrettyTable(
[str(self.display_title)], hrules=prettytable.ALL)
[str(self.display_title)], hrules=prettytable.ALL
)
t.align = 'l'
for name, result in check_results:
cell = (
_('Check: %(name)s\n'
'Result: %(result)s\n'
'Details: %(details)s') %
{
'name': name,
'result': UPGRADE_CHECK_MSG_MAP[result.code],
'details': self._get_details(result),
}
)
cell = _(
'Check: %(name)s\nResult: %(result)s\nDetails: %(details)s'
) % {
'name': name,
'result': UPGRADE_CHECK_MSG_MAP[result.code],
'details': self._get_details(result),
}
t.add_row([cell])
print(t)
@@ -171,6 +178,7 @@ def register_cli_options(conf, upgrade_command):
upgrade check arguments.
:param upgrade_command: The UpgradeCommands instance.
"""
def add_parsers(subparsers):
upgrade_action = subparsers.add_parser('upgrade')
upgrade_action.add_argument('check')
@@ -179,7 +187,8 @@ def register_cli_options(conf, upgrade_command):
'--json',
action='store_true',
help='Output the results in JSON format. Default is to print '
'results in human readable table format.')
'results in human readable table format.',
)
opt = cfg.SubCommandOpt('command', handler=add_parsers)
conf.register_cli_opt(opt)
@@ -199,9 +208,13 @@ def run(conf):
return 255
def main(conf, project, upgrade_command,
argv=sys.argv[1:],
default_config_files=None):
def main(
conf,
project,
upgrade_command,
argv=sys.argv[1:],
default_config_files=None,
):
"""Simple implementation of main for upgrade checks
This can be used in upgrade check commands to provide the minimum
@@ -223,10 +236,6 @@ def main(conf, project, upgrade_command,
global CONF
register_cli_options(conf, upgrade_command)
conf(
args=argv,
project=project,
default_config_files=default_config_files,
)
conf(args=argv, project=project, default_config_files=default_config_files)
CONF = conf
return run(conf)

View File

@@ -34,3 +34,21 @@ Repository = "https://opendev.org/openstack/oslo.upgradecheck"
packages = [
"oslo_upgradecheck"
]
[tool.ruff]
line-length = 79
[tool.ruff.lint]
select = ["C4", "E4", "E5", "E7", "E9", "F", "S", "UP"]
ignore = [
# we only use asserts for type narrowing
"S101",
]
[tool.ruff.lint.per-file-ignores]
"oslo_upgradecheck/tests/*" = ["S"]
[tool.ruff.format]
quote-style = "preserve"
docstring-code-format = true
skip-magic-trailing-comma = true

View File

@@ -33,10 +33,7 @@ release = ''
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'reno.sphinxext',
'openstackdocstheme',
]
extensions = ['reno.sphinxext', 'openstackdocstheme']
# The master toctree document.
master_doc = 'index'

View File

@@ -15,6 +15,4 @@
import setuptools
setuptools.setup(
setup_requires=['pbr'],
pbr=True)
setuptools.setup(setup_requires=['pbr'], pbr=True)

11
tox.ini
View File

@@ -59,11 +59,14 @@ commands =
commands = oslo_debug_helper {posargs}
[flake8]
# E123, E125 skipped as they are invalid PEP-8.
# We only enable the hacking (H) checks
select = H
# H301 Black will put commas after imports that can't fit on one line
# H404 Docstrings don't always start with a newline
# H405 Multiline docstrings are okay
ignore = H301,H403,H404,H405
show-source = True
ignore = E123,E125,W504
builtins = _
exclude=.venv,.git,.tox,dist,doc,releasenotes,*lib/python*,*egg,build
exclude = .venv,.git,.tox,dist,doc,releasenotes,*lib/python*,*egg,build
[hacking]
import_exception = oslo_upgradecheck._i18n