Exemplo n.º 1
0
class FirstActor(Actor):
    name = 'first_actor'
    description = 'No description has been provided for the first_actor actor.'
    consumes = ()
    produces = ()
    tags = (FirstPhaseTag, UnitTestWorkflowTag)
    dialogs = (
        Dialog(
            scope='unique_dialog_scope',
            reason='Confirmation',
            components=(
                BooleanComponent(
                    key='confirm',
                    label='Disable a deprecated module?'
                          'If no, the upgrade process will be interrupted.',
                    default=False,
                    description='Module XXX is no longer available '
                                'in RHEL-8 since it was replaced by shiny-metal-XXX.',
                    reason='Leaving this module in system configuration may lock out the system.'
                ),
            )
        ),)

    def process(self):
        from leapp.libraries.common.test_helper import log_execution
        log_execution(self)
        if not self.configuration or self.configuration.value != 'unit-test':
            self.report_error('Unit test failed due missing or invalid workflow provided configuration')
        if os.environ.get('FirstActor-ReportError') == '1':
            self.report_error("Unit test requested error")
        self.request_answers(self.dialogs[0]).get('confirm', False)
Exemplo n.º 2
0
class WarnUserPython2Scripts(Actor):
    name = 'warn_user_python2_scripts'
    description = 'No description has been provided for the warn_user_python2_scripts actor.'
    consumes = (DetectedPython2Scripts,)
    produces = ()
    tags = (ChecksPhaseTag, IPUWorkflowTag)
    dialogs = (
        Dialog(
            scope='warn_python2_user_scripts',
            title='Warning Python 2.x scripts detected',
            reason='''
Python 2.x has been depreated and it is no longer supported by Fedora.
You have the option to review the list of scripts that potentially will
no longer work with the python3 installation.'''.strip(),
            components=(
            BooleanComponent(
                key='display',
                default=False,
                label='Would you like to display the affected scripts?'),)),
        Dialog(
            scope='continue_warn_python2_user_scripts',
            title='',
            reason='',
            components=(
                BooleanComponent(
                    key='continue',
                    default=True,
                    label='Continue with upgrade?'),)))

    def process(self):
        scripts = list(self.consume(DetectedPython2Scripts))
        if scripts and self.request_answers(self.dialogs[0]).get('display', False):
            all_scripts = set()
            for message in scripts:
                all_scripts.update(message.scripts)
            print('- ' + '\n- '.join(all_scripts), '\n')
            if not self.request_answers(self.dialogs[1]).get('continue', False):
                self.report_error('User requested abortion')
Exemplo n.º 3
0
class SuggestServiceNewDefaults(Actor):
    name = 'suggest_service_new_defaults'
    description = 'No description has been provided for the suggest_service_new_defaults actor.'
    consumes = ()
    produces = ()
    tags = (ChecksPhaseTag, IPUWorkflowTag)
    dialogs = (Dialog(scope='new_service_defaults_dialog',
                      title='New service defaults',
                      reason='''
In the new version of Fedora changes have been made to the service defaults
and we detected customizations to your service defaults. Please select one
of the following strategies to use for the upgrade.'''.strip(),
                      components=(ChoiceComponent(key='strategy',
                                                  label='Strategy to use',
                                                  default=_CHOICES[1],
                                                  choices=_CHOICES), )), )

    def process(self):
        self.request_answers(self.dialogs[0])
Exemplo n.º 4
0
class SuggestPython2Module(Actor):
    name = 'suggest_python2_module'
    description = 'No description has been provided for the suggest_python2_module actor.'
    consumes = (DetectedPython2Scripts, )
    produces = ()
    tags = (ChecksPhaseTag, IPUWorkflowTag)
    dialogs = (Dialog(scope='suggest_python2_module',
                      title='Python 2.7 module stream',
                      reason=_DIALOG_REASON.strip(),
                      components=(ChoiceComponent(
                          key='switch',
                          choices=_AVAILABLE_CHOICES,
                          default=_AVAILABLE_CHOICES[1],
                          label='How would you like to continue'), )), )

    def process(self):
        if self.consume(DetectedPython2Scripts):
            result = self.request_answers(self.dialogs[0]).get('switch')
            if _AVAILABLE_CHOICES.index(result) == 2:
                self.report_error('User requested abortion')
Exemplo n.º 5
0
class AskToSwitchToBls(Actor):
    name = 'ask_to_switch_to_bls'
    description = 'No description has been provided for the ask_to_switch_to_bls actor.'
    consumes = ()
    produces = (SwitchToBLS, )
    tags = (IPUWorkflowTag, FactsPhaseTag)
    dialogs = (Dialog(scope='switch_to_bls',
                      reason='''
The Boot Loader Specification (BLS) defines a scheme and file format to manage
boot loader configuration for each boot option in a drop-in directory, without
the need to manipulate bootloader configuration files. Directories of
individual drop-in configuration files are standard for many purposes on Linux
nowadays, so the goal is to also extend this concept for boot menu entries.'''.
                      strip(),
                      title='Convert to Boot Loader Specification?',
                      components=(BooleanComponent(
                          key='answer',
                          default=False,
                          label='Would you like to switch?'), )), )

    def process(self):
        if self.request_answers(self.dialogs[0]).get('answer', False):
            self.produce(SwitchToBLS(value=True))
Exemplo n.º 6
0
class AuthselectCheck(Actor):
    """
    Confirm suggested authselect call from AuthselectScanner.

    AuthselectScanner produces an Authselect model that contains changes
    that are suggested based on current configuration. This actor will
    ask administrator for confirmation and will report the result.
    """

    name = 'authselect_check'
    consumes = (Authselect,)
    produces = (AuthselectDecision, Report,)
    tags = (IPUWorkflowTag, ChecksPhaseTag)
    dialogs = (
        Dialog(
            scope='authselect_check',
            reason='Confirmation',
            components=(
                BooleanComponent(
                    key='confirm',
                    label='Configure PAM and nsswitch.conf with the following '
                          'authselect call?',
                    default=True,
                    description='If yes, suggested authselect profile will '
                                'be applied on your system to generate '
                                'PAM and nsswitch.conf configuration. '
                                'If no, current configuration will be kept '
                                'intact.',
                    reason='There is a new tool called authselect in RHEL8 '
                           'that replaced authconfig which is used to manage '
                           'authentication (PAM) and identity (nsswitch.conf) '
                           'sources. It is recommended to switch to this tool.'
                ),
            )
        ),
    )

    def process(self):
        model = next(self.consume(Authselect))

        # If there is no equivalent authselect profile we will not touch
        # the current configuration. Therefore there is no need for
        # confirmation.
        if model.profile is None:
            self.produce_current_configuration(model)
            return

        command = 'authselect select {0} {1} --force'.format(
            model.profile,
            ' '.join(model.features)
        )

        # We do not need admin confirmation if the current
        # configuration was generated with authconfig.
        if not model.confirm:
            self.produce_authconfig_configuration(model, command)
            return

        # Authselect profile is available but we require confirmation.
        confirmed = self.get_confirmation(model, command)
        if confirmed is not None:
            # A user has made his choice
            self.produce_suggested_configuration(model, confirmed, command)

    def get_confirmation(self, model, command):
        dialog = self.dialogs[0]

        dialog.components[0].label += "\n{}\n".format(command)

        return self.get_answers(dialog).get('confirm')

    def produce_authconfig_configuration(self, model, command):
        self.produce(
            AuthselectDecision(
                confirmed=True
            )
        )

        create_report([
            reporting.Title(
                'Authselect will be used to configure PAM and nsswitch.conf.'
            ),
            reporting.Summary(
                'There is a new tool called authselect in RHEL8 that '
                'replaced authconfig. The upgrade process detected '
                'that authconfig was used to generate current '
                'configuration and it will automatically convert it '
                'to authselect. Authselect call is: {}. The process will '
                'also enable "oddjobd" systemd service on startup'.format(command)
            ),
            reporting.Tags([
                reporting.Tags.AUTHENTICATION,
                reporting.Tags.SECURITY,
                reporting.Tags.TOOLS
            ])
        ] + resources)

    def produce_current_configuration(self, model):
        self.produce(
            AuthselectDecision(
                confirmed=False
            )
        )

        create_report([
            reporting.Title(
                'Current PAM and nsswitch.conf configuration will be kept.'
            ),
            reporting.Summary(
                'There is a new tool called authselect in RHEL8 that '
                'replaced authconfig. The upgrade process was unable '
                'to find an authselect profile that would be equivalent '
                'to your current configuration. Therefore your '
                'configuration will be left intact.'
            ),
            reporting.Tags([
                reporting.Tags.AUTHENTICATION,
                reporting.Tags.SECURITY,
                reporting.Tags.TOOLS
            ]),
            reporting.Severity(reporting.Severity.INFO)
        ] + resources)

    def produce_suggested_configuration(self, model, confirmed, command):
        self.produce(
            AuthselectDecision(
                confirmed=confirmed
            )
        )
        if confirmed:
            create_report([
                reporting.Title(
                    'Authselect will be used to configure PAM and nsswitch.conf.'
                ),
                reporting.Summary(
                    'There is a new tool called authselect in RHEL8 that '
                    'replaced authconfig. The upgrade process suggested '
                    'an authselect profile that is similar to your '
                    'current configuration and your system will be switched '
                    'to this profile. Authselect call is: {}. The process will '
                    'also enable "oddjobd" systemd service on startup'.format(command)
                ),
                reporting.Tags([
                    reporting.Tags.AUTHENTICATION,
                    reporting.Tags.SECURITY,
                    reporting.Tags.TOOLS
                ])
            ] + resources)

        else:
            create_report([
                reporting.Title(
                    'Current PAM and nsswitch.conf configuration will be kept.'
                ),
                reporting.Summary(
                    'There is a new tool called authselect in RHEL8 that '
                    'replaced authconfig. The upgrade process suggested '
                    'an authselect profile that is similar to your '
                    'current configuration. However this suggestion was '
                    'refused therefore existing configuration will be kept '
                    'intact.',
                ),
                reporting.Tags([
                    reporting.Tags.AUTHENTICATION,
                    reporting.Tags.SECURITY,
                    reporting.Tags.TOOLS
                ]),
                reporting.Remediation(commands=[[command]]),
                reporting.Severity(reporting.Severity.MEDIUM)
            ] + resources)
Exemplo n.º 7
0
class FirewallDecision(Actor):
    name = 'firewalld_decision'
    description = 'Firewall disable decision maker actor (pre-reboot) (check phase).'
    consumes = (SystemFacts, )
    produces = (
        FirewallDecisionM,
        CheckResult,
    )
    tags = (
        IPUWorkflowTag,
        ChecksPhaseTag,
        ExperimentalTag,
    )
    dialogs = (Dialog(
        scope='continue_fw',
        reason=
        'FirewallD and/or IPTables are not supported by the upgrade process!\n'
        'Please choose whether you would like to proceed and let the upgrade\n'
        'disable the firewall. Answering \'N\' will stops the upgrade process',
        title=
        'FirewallD and/or IPTables needs to be shutdown, please, confirm!',
        components=(BooleanComponent(
            key='continue_fw',
            label='Shall the upgrade process disable the firewall',
            default=False), ),
    ), )

    def process(self):
        self.log.info("Starting to get FirewallD decision.")
        for facts in self.consume(SystemFacts):
            # FIXME: checked only whether services are disabled. But in case
            # + there is another service/proces/... that starts firewalls during
            # + boot we will not catch it in this way. Shouldn't we check and
            # + print warning message in case the firewalls are active but
            # + services are disabled? To reflect possible risk, e.g. that user
            # + will not be able to connect to the upgraded system through ssh.
            # + Fix it later.
            if facts.firewalls.firewalld.enabled or facts.firewalls.iptables.enabled:
                answer = self.request_answers(self.dialogs[0]).get(
                    'continue_fw', False)
                self.produce(
                    FirewallDecisionM(disable_choice='Y' if answer else 'N'))
                if not answer:
                    self.produce(
                        CheckResult(
                            severity='Error',
                            result='Fail',
                            summary=
                            'Firewall interrupts upgrade process request',
                            details='SA user chose to interrupt the upgrade.',
                            solutions=None))
                return
            else:
                # FIXME: See the fixme above
                self.log.info("Firewall is disabled. Nothing to decide.")
                self.produce(FirewallDecisionM(disable_choice='S'))
                self.produce(
                    CheckResult(severity='Info',
                                result='Pass',
                                summary='Firewall disabled',
                                details='Firewall service is disabled.',
                                solutions=None))
                return
        else:
            self.log.info(
                "No message to consume for the Firewall decision. Quitting..")
        return
Exemplo n.º 8
0
class RemoveOldPAMModulesCheck(Actor):
    """
    Check if it is all right to disable PAM modules that are not in RHEL-8.

    If admin will refuse to disable these modules (pam_pkcs11 and pam_krb5),
    upgrade will be stopped. Otherwise we would risk locking out the system
    once these modules are removed.
    """
    name = 'removed_pam_modules_check'
    consumes = (RemovedPAMModules,)
    produces = (Report,)
    tags = (IPUWorkflowTag, ChecksPhaseTag)
    dialogs = (
        Dialog(
            scope='remove_pam_pkcs11_module_check',
            reason='Confirmation',
            components=(
                BooleanComponent(
                    key='confirm',
                    label='Disable pam_pkcs11 module in PAM configuration? '
                          'If no, the upgrade process will be interrupted.',
                    description='PAM module pam_pkcs11 is no longer available '
                                'in RHEL-8 since it was replaced by SSSD.',
                    reason='Leaving this module in PAM configuration may '
                           'lock out the system.'
                ),
            )
        ),
        Dialog(
            scope='remove_pam_krb5_module_check',
            reason='Confirmation',
            components=(
                BooleanComponent(
                    key='confirm',
                    label='Disable pam_krb5 module in PAM configuration? '
                          'If no, the upgrade process will be interrupted.',
                    description='PAM module pam_krb5 is no longer available '
                                'in RHEL-8 since it was replaced by SSSD.',
                    reason='Leaving this module in PAM configuration may '
                           'lock out the system.'
                ),
            )
        ),
    )

    modules = []

    def process(self):
        model = next(self.consume(RemovedPAMModules))

        for module in model.modules:
            result = self.confirm(module)
            if result:
                self.produce_report(module)
            elif result is False:
                # user specifically chose to disagree with auto disablement
                self.produce_inhibitor(module)

    def confirm(self, module):
        questions = {
            'pam_pkcs11': self.dialogs[0],
            'pam_krb5': self.dialogs[1]
        }

        return self.get_answers(questions[module]).get('confirm')

    def produce_report(self, module):
        create_report([
            reporting.Title('Module {0} will be removed from PAM configuration'.format(module)),
            reporting.Summary(
                'Module {0} was surpassed by SSSD and therefore it was '
                'removed from RHEL-8. Keeping it in PAM configuration may '
                'lock out the system thus it will be automatically removed '
                'from PAM configuration before upgrading to RHEL-8. '
                'Please switch to SSSD to recover the functionality '
                'of {0}.'.format(module)
            ),
            reporting.Severity(reporting.Severity.MEDIUM),
            reporting.Tags([
                    reporting.Tags.AUTHENTICATION,
                    reporting.Tags.SECURITY,
                    reporting.Tags.TOOLS
            ]),
            reporting.Remediation(hint='Configure SSSD to replace {0}'.format(module)),
            reporting.RelatedResource('package', 'sssd')
        ])

    def produce_inhibitor(self, module):
        create_report([
            reporting.Title(
                'Upgrade process was interrupted because {0} is enabled in '
                'PAM configuration and SA user refused to disable it '
                'automatically.'.format(module)),
            reporting.Summary(
                'Module {0} was surpassed by SSSD and therefore it was '
                'removed from RHEL-8. Keeping it in PAM configuration may '
                'lock out the system thus it is necessary to disable it '
                'before the upgrade process can continue.'.format(module)
            ),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([
                    reporting.Tags.AUTHENTICATION,
                    reporting.Tags.SECURITY,
                    reporting.Tags.TOOLS
            ]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
            reporting.Remediation(
                hint='Disable {0} module and switch to SSSD to recover its functionality.'.format(module)),
            reporting.RelatedResource('package', 'sssd')
        ])
Exemplo n.º 9
0
from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
from leapp.dialogs import Dialog, ChoiceComponent

_AVAILABLE_CHOICES = ('Switch to 9.x stream', 'Upgrade to latest',
                      'Abort upgrade')
_DIALOG_REASON = '''
We detected PostgreSQL version 9.x on your system.  The new version of Fedora
gives you the opportunity to switch to a PostgeSQL 9.x module stream. An
alternative choice you have, is to upgrade your PostgreSQL installation to
the latest version.
'''

_DIALOGS = (Dialog(scope='postgresql_module_switch',
                   title='PostgreSQL 9.X module stream',
                   reason=_DIALOG_REASON.strip(),
                   components=(ChoiceComponent(
                       key='switch',
                       choices=_AVAILABLE_CHOICES,
                       default=_AVAILABLE_CHOICES[1],
                       label='How would you like to continue'), )), )


class SuggestModulePostgreSql(Actor):
    name = 'suggest_module_postgre_sql'
    description = 'No description has been provided for the suggest_module_postgre_sql actor.'
    consumes = (DetectedPostgreSql, )
    produces = ()
    tags = (ChecksPhaseTag, IPUWorkflowTag)
    dialogs = _DIALOGS

    def process(self):
        for detection in self.consume(DetectedPostgreSql):
Exemplo n.º 10
0
class RemoveOldPAMModulesCheck(Actor):
    """
    Check if it is all right to disable PAM modules that are not in RHEL-8.

    If admin will refuse to disable these modules (pam_pkcs11 and pam_krb5),
    upgrade will be stopped. Otherwise we would risk locking out the system
    once these modules are removed.
    """
    name = 'removed_pam_modules_check'
    consumes = (RemovedPAMModules, )
    produces = (Report, )
    tags = (IPUWorkflowTag, ChecksPhaseTag, ExperimentalTag)
    dialogs = (
        Dialog(scope='remove_pam_pkcs11_module_check',
               reason='Confirmation',
               components=(BooleanComponent(
                   key='confirm',
                   label='Disable pam_pkcs11 module in PAM configuration? '
                   'If no, the upgrade process will be interrupted.',
                   default=False,
                   description='PAM module pam_pkcs11 is no longer available '
                   'in RHEL-8 since it was replaced by SSSD.',
                   reason='Leaving this module in PAM configuration may '
                   'lock out the system.'), )),
        Dialog(scope='remove_pam_krb5_module_check',
               reason='Confirmation',
               components=(BooleanComponent(
                   key='confirm',
                   label='Disable pam_krb5 module in PAM configuration? '
                   'If no, the upgrade process will be interrupted.',
                   default=False,
                   description='PAM module pam_krb5 is no longer available '
                   'in RHEL-8 since it was replaced by SSSD.',
                   reason='Leaving this module in PAM configuration may '
                   'lock out the system.'), )),
    )

    modules = []

    def process(self):
        model = next(self.consume(RemovedPAMModules))

        for module in model.modules:
            result = self.confirm(module)
            if result:
                self.produce_report(module)
            else:
                self.produce_inhibitor(module)

    def confirm(self, module):
        questions = {
            'pam_pkcs11': self.dialogs[0],
            'pam_krb5': self.dialogs[1]
        }

        return self.request_answers(questions[module]).get('confirm', False)

    def produce_report(self, module):
        report_with_remediation(
            title='Module {0} will be removed from PAM configuration'.format(
                module),
            summary='Module {0} was surpassed by SSSD and therefore it was '
            'removed from RHEL-8. Keeping it in PAM configuration may '
            'lock out the system thus it will be automatically removed '
            'from PAM configuration before upgrading to RHEL-8. '
            'Please switch to SSSD to recover the functionality '
            'of {0}.'.format(module),
            remediation='Configure SSSD to replace {0}'.format(module))

    def produce_inhibitor(self, module):
        report_with_remediation(
            title='Upgrade process was interrupted because {0} is enabled in '
            'PAM configuration and SA user refused to disable it '
            'automatically.'.format(module),
            summary='Module {0} was surpassed by SSSD and therefore it was '
            'removed from RHEL-8. Keeping it in PAM configuration may '
            'lock out the system thus it is necessary to disable it '
            'before the upgrade process can continue.'.format(module),
            remediation='Disable {0} module and switch to SSSD to recover '
            'its functionality.'.format(module),
            flags=['inhibitor'])