Skip to content

provision --update fails when used with execute upgrade plugin #4456

@guazhang

Description

@guazhang

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

  1. 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
  1. 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

  1. Parent plan execution starts with CLI invocations stored in Step.cli_invocations class variable
  2. Upgrade plugin loads a plan from the remote repository at tmt/steps/execute/upgrade.py:416:
    plan = self._get_plan(self._discover_upgrade.testdir)
  3. New Plan initialization triggers Step.__init__() which calls _apply_cli_invocations() at tmt/steps/__init__.py:561
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Waiting contactNo response on github and cannot contact another way

    Type

    No type

    Projects

    Status

    done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions