Skip to content

Action Framework

Toshio Kuratomi edited this page May 8, 2023 · 10 revisions

Action Framework

WARNING: This feature is currently in a Technical Preview.

The Action Framework allows Convert2RHEL to execute a pre conversion analysis that will let the user identify if the conversion will be successful up to the point of the return.

Action Classes

Action classes are a way to implement checks that needs to run during the conversion to identify any problems with the system before we reach to a critical part of the conversion called Point of no Return.

Examples

Normal action class for a regular check that does not depend on anything else and will execute flawlessly.

__metaclass__ = type

from convert2rhel import actions 
import logging

logger = logging.getLogger(__name__)

class YourAction(actions.Action):
    # `id` is always required for the Action.
    id = "YOUR_ACTION"

    # `dependencies` is optional. If you aciton doesn't have any dependency, 
    # you don't need that field to be present.
    dependencies = ()

    def run(self):
        super(YourAction, self).run()

        logger.task("Performing very important task!")
        perform_your_very_important_task()

Action class that set a different result after it's execution. Usually, the self.set_result() function is used to set error results after the execution.

__metaclass__ = type

from convert2rhel import actions 
import logging

logger = logging.getLogger(__name__)

class YourAction(actions.Action):
    id = "YOUR_ACTION"

    def run(self):
        super(YourAction, self).run()

        logger.task("Performing a task that will fail :(")
        has_failed = a_task_that_will_fail()

        if has_failed:
            # In case of failure, you need to set the result 
            self.set_result(status="ERROR", error_id="SOME_ERROR", message="It failed :(")
        else:
            self.set_result(status="WARNING", error_id="SOME_WARNING", message="It succeed, but with some warnings.")

Below, an example has actions with dependencies

__metaclass__ = type

from convert2rhel import actions 
import logging

logger = logging.getLogger(__name__)

class YourDependencyAction(actions.Action)
    id = "NICE_DEPENDENCY"

    def run(self):
        super(YourDependencyAction, self).run()
        
        logger.info("This action class will run first")
        perform_some_dependency_thing()

class YourAction(actions.Action):
    id = ""
    dependencies = (
        "NICE_DEPENDENCY",
        # Or, you could use, which ideally is the same as the above.
        YourDependencyAction.id,    
    )

    def run(self):
        super(YourAction, self).run()

        logger.info("This action will run if `YourDependencyAction` succeed.")
        now_we_execute_this_action()

Regarding the above examples, whenever we have dependencies in an action class, the dependency will run first, and if the dependency succeeds, your action will ran and execute it's own code, otherwise, if the dependency failed, an SKIP status will be set for the dependency, and any dependant action will not execute.

A note on dependencies

Dependencies are normal actions that are supposed to ensure that specific code will run before your main action. Usually, dependencies are used to perform setups, cleanups, or any other action that needs to prepare a specific behavior before an determinated action runs.

Another way of using dependencies, is to ensure correct ordering of action runs. By default, the Action Framework will run actions in different orders if they don't have any dependencies, making this a bit harder to ensure that the actions will always run and keep the same order of execution.

In order to overcome this situation, actions can depend on each other to ensure that they will run only after the successful state of the dependent action.

Down below, you can see a very minimalistic example of how the actions structure are supposed to be.

Actions folder structure

actions/
├── __init__.py                     # The main module where all actions related functions and classes are stored.
├── pre_ponr_changes                # Module that keep together all pre point of no return actions.
│   ├── handle_packages.py
│   ├── __init__.py
│   ├── kernel_modules.py
│   ├── special_cases.py
│   ├── subscription.py
│   └── transaction.py
├── report.py                       # The report module where wwe output a summary to the user regarding the action runs.
└── system_checks                   # Module that keep together all system checks actions.
    ├── convert2rhel_latest.py
    ├── custom_repos_are_valid.py
    ├── dbus.py
    ├── efi.py
    ├── __init__.py
    ├── is_loaded_kernel_latest.py
    ├── package_updates.py
    ├── readonly_mounts.py
    ├── rhel_compatible_kernel.py
    └── tainted_kmods.py

3 directories, 22 files

See Also

Report

The Action Framework counts with a report feature, which by the end of the execution of all actions, will output a summary to the user regarding if the failure/warnings of the actions executed. This report is especially useful for the users that want to do a pre analysis conversion before running the tool, allowing them to see, beforehand, if we have detected any problems which might prevent the conversion from succeeding.

The summary that we output is very simple, it consists of reporting about tasks that either failed, had an warning, were skipped because of a dependency failure, or failed but allow the user to override the check if they run convert2rhel again.It is good to note that the report described above is only when the user is doing a normal conversion. In case that the user is doing a pre analysis conversion, then we gonna output all logs in the report, as more information may be needed before progressing with the conversion.

Example of report messages in case of some actions not completing successfully:

[03/31/2023 17:43:52] TASK - [Prepare: Conversion analysis report] **********************************

(ERROR) ErrorAction.ERROR: ERROR MESSAGE
(OVERRIDABLE) OverridableAction.OVERRIDABLE: OVERRIDABLE MESSAGE
(WARNING) WarningAction.WARNING: WARNING MESSAGE

Example of report in case of all actions succeeding and no report is needed to be presented

[03/31/2023 17:43:52] TASK - [Prepare: Conversion analysis report] **********************************

No problems detected during the analysis!

The messages that are report in the summary will always be sorted in order of severity, so the list will always go like:

  • ERROR
  • OVERRIDABLE
  • SKIP
  • WARNING
  • SUCCESS