Description
When running TMT with the upgrade execute plugin, CLI invocations containing provision --update --name <phase-name> fail with the
error:
Cannot update phase '<phase-name>', no such name was found.
This occurs because CLI invocations from the parent plan are applied to the dynamically loaded upgrade plan, which may not have a
provision phase with the specified name.
Environment
- TMT Version: 1.62.1
- Python Version: 3.13
- OS: RHEL 10.2
Steps to Reproduce
- Create a plan with upgrade execution that uses
provision --update:
tmt run -f --all -dv \
provision --update -h beaker --name common \
--hardware hostname=storageqe-90.lab.eng.brq2.redhat.com \
--image RHEL-10.2-20251217.0 \
plan --name /plan/udisks2/base/fast
- The plan uses the upgrade execute method:
execute:
- how: upgrade
url: https://gitlab.cee.redhat.com/oamg/rhel-major-upgrade.git
upgrade-path: /paths/9to10.cut
TMT fails with:
execute step failed
The exception was caused by 1 earlier exceptions
Cause number 1:
Cannot update phase 'common', no such name was found.
Traceback (most recent call last):
File /usr/lib/python3.13/site-packages/tmt/queue.py, line 91, in _extract_task_outcome
task.result = extract(*args, **kwargs)
File /usr/lib64/python3.13/concurrent/futures/_base.py, line 449, in result
return self.__get_result()
File /usr/lib64/python3.13/concurrent/futures/_base.py, line 401, in __get_result
raise self._exception
File /usr/lib64/python3.13/concurrent/futures/thread.py, line 59, in run
result = self.fn(*self.args, **self.kwargs)
File /usr/lib/python3.13/site-packages/tmt/steps/__init__.py, line 2753, in run_on_guest
return self.phase.go(guest=guest, logger=logger)
File /usr/lib/python3.13/site-packages/tmt/steps/execute/upgrade.py, line 271, in go
self._perform_upgrade(guest, logger)
File /usr/lib/python3.13/site-packages/tmt/steps/execute/upgrade.py, line 416, in _perform_upgrade
plan = self._get_plan(self._discover_upgrade.testdir)
File /usr/lib/python3.13/site-packages/tmt/steps/execute/upgrade.py, line 290, in _get_plan
plans = tree.plans(names=[self.upgrade_path])
File /usr/lib/python3.13/site-packages/tmt/base.py, line 4189, in plans
Plan(
File /usr/lib/python3.13/site-packages/tmt/base.py, line 2195, in __init__
self.provision = tmt.steps.provision.Provision(
File /usr/lib/python3.13/site-packages/tmt/steps/provision/__init__.py, line 3509, in __init__
super().__init__(plan=plan, data=data, logger=logger)
File /usr/lib/python3.13/site-packages/tmt/steps/__init__.py, line 561, in __init__
raw_data = self._apply_cli_invocations(raw_data)
File /usr/lib/python3.13/site-packages/tmt/steps/__init__.py, line 1136, in _apply_cli_invocations
raise GeneralError(
Root Cause Analysis
Code Flow
- Parent plan execution starts with CLI invocations stored in
Step.cli_invocations class variable
- Upgrade plugin loads a plan from the remote repository at
tmt/steps/execute/upgrade.py:416:
plan = self._get_plan(self._discover_upgrade.testdir)
- New Plan initialization triggers
Step.__init__() which calls _apply_cli_invocations() at tmt/steps/__init__.py:561
- CLI invocations are applied from the parent plan to the loaded upgrade plan at
tmt/steps/__init__.py:1127-1146:
elif invocation.options.get('update'):
needle = invocation.options.get('name')
if needle:
for raw_datum in raw_data:
if raw_datum['name'] != needle:
continue
# ... update the phase
break
else:
raise GeneralError(
f"Cannot update phase '{needle}', no such name was found."
)
The Problem
While the upgrade plugin sets ignore_class_options = True to ignore plan-level CLI options (line 289), this does not prevent
step-level CLI invocations like provision --update from being applied to the loaded plan.
The loaded upgrade plan may have:
- A different provision phase name (not 'common')
- No provision phase at all
- A completely different structure
This causes the --update invocation to fail because there's no phase named 'common' in the loaded plan.
Description
When running TMT with the
upgradeexecute plugin, CLI invocations containingprovision --update --name <phase-name>fail with theerror:
This occurs because CLI invocations from the parent plan are applied to the dynamically loaded upgrade plan, which may not have a
provision phase with the specified name.
Environment
Steps to Reproduce
provision --update:tmt run -f --all -dv \ provision --update -h beaker --name common \ --hardware hostname=storageqe-90.lab.eng.brq2.redhat.com \ --image RHEL-10.2-20251217.0 \ plan --name /plan/udisks2/base/fastTMT fails with:
Root Cause Analysis
Code Flow
Step.cli_invocationsclass variabletmt/steps/execute/upgrade.py:416:Step.__init__()which calls_apply_cli_invocations()attmt/steps/__init__.py:561tmt/steps/__init__.py:1127-1146:The Problem
While the upgrade plugin sets
ignore_class_options = Trueto ignore plan-level CLI options (line 289), this does not preventstep-level CLI invocations like
provision --updatefrom being applied to the loaded plan.The loaded upgrade plan may have:
This causes the
--updateinvocation to fail because there's no phase named 'common' in the loaded plan.