def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--noop',
                        action='store_true',
                        dest='noop',
                        help='run script without installing')
    parser.add_argument(
        '--backup-repos',
        action='store_true',
        dest='backup',
        help='backup/restore yum repos instead overriding them')
    args = parser.parse_args()
    noop = args.noop
    backup_repos = args.backup

    logger = logging.getLogger("argo-poem-packages")
    logger.setLevel(logging.INFO)

    stdout = logging.StreamHandler()
    if not noop:
        stdout.setLevel(logging.WARNING)

    stdout.setFormatter(logging.Formatter("%(levelname)s - %(message)s"))
    logger.addHandler(stdout)

    # setting up logging to file
    logfile = logging.handlers.RotatingFileHandler(LOGFILE,
                                                   maxBytes=512 * 1024,
                                                   backupCount=5)
    logfile.setLevel(logging.INFO)
    logfile.setFormatter(
        logging.Formatter(
            "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
            "%Y-%m-%d %H:%M:%S"))

    # add the handler to the root logger
    logger.addHandler(logfile)

    try:
        subprocess.call(['yum', 'clean', 'all'])

        config = Config()
        token = config.get_token()
        hostname = config.get_hostname()
        profiles = config.get_profiles()

        logger.info('Sending request for profile(s): ' + ', '.join(profiles))
        if backup_repos:
            repos = YUMRepos(hostname=hostname,
                             token=token,
                             profiles=profiles,
                             override=False)

        else:
            repos = YUMRepos(hostname=hostname, token=token, profiles=profiles)

        data = repos.get_data()

        if not data:
            logger.warning('No data for given metric profile(s): ' +
                           ', '.join(profiles))
            sys.exit(2)

        else:
            logger.info('Creating YUM repo files...')

            files = repos.create_file()

            logger.info('Created files: ' + '; '.join(files))

            pkg = Packages(data)

            if noop:
                info_msg, warn_msg = pkg.no_op()

            else:
                info_msg, warn_msg = pkg.install()

            # if there were repo files backed up, now they are restored
            repos.clean()

            if info_msg:
                for msg in info_msg:
                    logger.info(msg)

            if warn_msg:
                for msg in warn_msg:
                    logger.warning(msg)

                sys.exit(1)

            else:
                missing_packages_msg = ''
                if repos.missing_packages:
                    missing_packages_msg = \
                        'Missing packages for given distro: ' + \
                        ', '.join(repos.missing_packages)
                    logger.warning(missing_packages_msg)

                if not noop:
                    if missing_packages_msg:
                        print('WARNING: ' + missing_packages_msg)

                logger.info("The run finished successfully.")
                sys.exit(0)

    except requests.exceptions.ConnectionError as err:
        logger.error(err)
        sys.exit(2)

    except requests.exceptions.RequestException as err:
        logger.error(err)
        sys.exit(2)

    except configparser.ParsingError as err:
        logger.error(err)
        sys.exit(2)

    except configparser.NoSectionError as err:
        logger.error(err)
        sys.exit(2)

    except configparser.NoOptionError as err:
        logger.error(err)
        sys.exit(2)

    except PackageException as err:
        logger.error(err)
        sys.exit(2)
示例#2
0
 def setUp(self):
     self.pkgs = Packages(data)
示例#3
0
def main():
    logger = logging.getLogger('argo-poem-packages')
    logger.setLevel(logging.INFO)

    # setting up logging to file
    logfile = logging.FileHandler('/var/log/messages')
    logfile.setLevel(logging.INFO)
    logfile.setFormatter(
        logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'))

    # add the handler to the root logger
    logger.addHandler(logfile)

    try:
        subprocess.call(['yum', 'clean', 'all'])

        config = Config()
        token = config.get_token()
        hostname = config.get_hostname()
        profiles = config.get_profiles()

        logger.info('Sending request for profile(s): ' + ', '.join(profiles))
        data = get_repo_data(build_api_url(hostname), token, profiles)

        if not data:
            logger.warning('No data for given metric profile(s): ' +
                           ', '.join(profiles))
            sys.exit(2)

        else:
            logger.info('Creating YUM repo files...')
            create_yum_repo_file(data)

            pkg = Packages(data)

            installed, not_installed, downgraded, not_downgraded = \
                pkg.install_packages()

            warn_msg = []
            info_msg = []
            if pkg.get_packages_not_found():
                warn_msg.append('Packages not found: ' +
                                ', '.join(pkg.get_packages_not_found()))

            if installed:
                new_installed = \
                    pkg.get_packages_installed_with_versions_as_requested(
                        installed
                    )

                if new_installed:
                    info_msg.append('Packages installed: ' +
                                    ', '.join(new_installed))

                installed_diff = \
                    pkg.get_packages_installed_with_different_version()

                if installed_diff:
                    info_msg.append(
                        'Packages installed with different version: ' +
                        ', '.join(installed_diff))

            if not_installed:
                warn_msg.append('Packages not installed: ' +
                                ', '.join(not_installed))

            if downgraded:
                info_msg.append('Packages downgraded: ' +
                                ', '.join(downgraded))

            if not_downgraded:
                warn_msg.append('Packages not downgraded: ' +
                                ', '.join(not_downgraded))

            if info_msg:
                logger.info('; '.join(info_msg))

            if warn_msg:
                logger.warning('; '.join(warn_msg))
                sys.exit(1)

            else:
                logger.info('ok!')
                sys.exit(0)

    except requests.exceptions.ConnectionError as err:
        logger.error(err)
        sys.exit(2)

    except requests.exceptions.RequestException as err:
        logger.error(err)
        sys.exit(2)

    except ConfigParser.ParsingError as err:
        logger.error(err)
        sys.exit(2)

    except ConfigParser.NoSectionError as err:
        logger.error(err)
        sys.exit(2)

    except ConfigParser.NoOptionError as err:
        logger.error(err)
        sys.exit(2)
示例#4
0
class PackageTests(unittest.TestCase):
    def setUp(self):
        self.pkgs = Packages(data)

    def test_get_package_list(self):
        self.assertEqual(
            set(self.pkgs.package_list), {('nagios-plugins-fedcloud', '0.5.0'),
                                          ('nagios-plugins-igtf', '1.4.0'),
                                          ('nagios-plugins-globus', '0.1.5'),
                                          ('nagios-plugins-argo', '0.1.12'),
                                          ('nagios-plugins-http', )})

    @mock.patch('argo_poem_tools.packages.subprocess.check_output')
    def test_get_available_packages(self, mock_yumdb):
        self.pkgs.versions_unlocked = True
        mock_yumdb.return_value = mock_yum_list_available
        self.assertEqual(self.pkgs._get_available_packages(), [
            dict(name='nagios', version='4.4.5', release='7.el7'),
            dict(name='nagios-contrib', version='4.4.5', release='7.el7'),
            dict(name='nagios-devel', version='4.4.5', release='7.el7'),
            dict(name='nagios-plugin-grnet-agora',
                 version='0.3',
                 release='20200731072952.4427855.el7'),
            dict(name='nagios-plugins-activemq',
                 version='1.0.0',
                 release='20170401112243.00c5f1d.el7'),
            dict(name='nagios-plugins-disk_smb',
                 version='2.3.3',
                 release='2.el7'),
            dict(name='nagios-plugins-globus',
                 version='0.1.5',
                 release='20200713050450.eb1e7d8.el7'),
            dict(name='nagios-plugins-gocdb',
                 version='1.0.0',
                 release='20200713050609.a481696.el7'),
            dict(name='NetworkManager-dispatcher-routing-rules',
                 version='1:1.18.4',
                 release='3.el7')
        ])

    @mock.patch('argo_poem_tools.packages.Packages._unlock_versions')
    @mock.patch('argo_poem_tools.packages.subprocess.check_output')
    def test_get_available_packages_if_versions_locked(self, mock_yumdb,
                                                       mock_unlock):
        mock_yumdb.return_value = mock_yum_list_available
        self.assertEqual(self.pkgs._get_available_packages(), [
            dict(name='nagios', version='4.4.5', release='7.el7'),
            dict(name='nagios-contrib', version='4.4.5', release='7.el7'),
            dict(name='nagios-devel', version='4.4.5', release='7.el7'),
            dict(name='nagios-plugin-grnet-agora',
                 version='0.3',
                 release='20200731072952.4427855.el7'),
            dict(name='nagios-plugins-activemq',
                 version='1.0.0',
                 release='20170401112243.00c5f1d.el7'),
            dict(name='nagios-plugins-disk_smb',
                 version='2.3.3',
                 release='2.el7'),
            dict(name='nagios-plugins-globus',
                 version='0.1.5',
                 release='20200713050450.eb1e7d8.el7'),
            dict(name='nagios-plugins-gocdb',
                 version='1.0.0',
                 release='20200713050609.a481696.el7'),
            dict(name='NetworkManager-dispatcher-routing-rules',
                 version='1:1.18.4',
                 release='3.el7')
        ])
        self.assertEqual(mock_unlock.call_count, 1)

    @mock.patch('argo_poem_tools.packages.subprocess.check_output')
    def test_get_locked_versions(self, mock_versionlock):
        mock_versionlock.return_value = mock_yum_versionlock_list
        self.pkgs._get_locked_versions()
        self.assertEqual(sorted(self.pkgs.locked_versions),
                         ['nagios-plugins-argo', 'nagios-plugins-fedcloud'])

    @mock.patch('argo_poem_tools.packages.subprocess.call')
    def test_unlock_versions(self, mock_call):
        self.pkgs.locked_versions = [
            'nagios-plugins-argo', 'nagios-plugins-fedcloud'
        ]
        self.assertEqual(self.pkgs.initially_locked_versions, [])
        mock_call.side_effect = mock_func
        self.pkgs._unlock_versions()
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_has_calls([
            mock.call(['yum', 'versionlock', 'delete', 'nagios-plugins-argo'],
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE),
            mock.call(
                ['yum', 'versionlock', 'delete', 'nagios-plugins-fedcloud'],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
        ],
                                   any_order=True)
        self.assertEqual(self.pkgs.initially_locked_versions,
                         ['nagios-plugins-argo', 'nagios-plugins-fedcloud'])

    @mock.patch('argo_poem_tools.packages.subprocess.call')
    def test_failsafe_lock_versions(self, mock_call):
        mock_call.side_effect = mock_func
        self.pkgs.initially_locked_versions = [
            'nagios-plugins-argo', 'nagios-plugins-fedcloud',
            'nagios-plugins-globus'
        ]
        self.pkgs.locked_versions = ['nagios-plugins-argo']
        self.pkgs._failsafe_lock_versions()
        self.assertEqual(mock_call.call_count, 3)
        mock_call.assert_has_calls([
            mock.call(['yum', 'versionlock', 'add', 'nagios-plugins-argo'],
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE),
            mock.call(['yum', 'versionlock', 'add', 'nagios-plugins-fedcloud'],
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE),
            mock.call(['yum', 'versionlock', 'add', 'nagios-plugins-globus'],
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE)
        ],
                                   any_order=True)

    @mock.patch('argo_poem_tools.packages.subprocess.check_output')
    @mock.patch('argo_poem_tools.packages.subprocess.call')
    def test_unlock_versions_if_none_locked(self, mock_call, mock_versionlock):
        mock_call.side_effect = mock_func
        mock_versionlock.return_value = mock_empty_versionlock_list
        self.assertEqual(self.pkgs.initially_locked_versions, [])
        self.pkgs._unlock_versions()
        self.assertEqual(mock_call.call_count, 0)
        self.assertEqual(self.pkgs.initially_locked_versions, [])

    @mock.patch('argo_poem_tools.packages.Packages._get_available_packages')
    def test_get_exceptions(self, mock_yumdb):
        mock_yumdb.return_value = [
            dict(name='nagios-plugins-fedcloud',
                 version='0.6.0',
                 release='20200511071632.05e2501.el7'),
            dict(name='nagios-plugins-igtf', version='1.4.0', release='3.el7'),
            dict(name='nagios-plugins-http', version='2.3.3', release='1.el7')
        ]
        self.pkgs._get_exceptions()
        self.assertEqual(self.pkgs.packages_different_version,
                         [('nagios-plugins-fedcloud', '0.6.0')])
        self.assertEqual(set(self.pkgs.packages_not_found),
                         {('nagios-plugins-globus', '0.1.5'),
                          ('nagios-plugins-argo', '0.1.12')})

    @mock.patch('argo_poem_tools.packages.subprocess.check_output')
    def test_get_installed_packages(self, mock_rpm):
        mock_rpm.return_value = mock_rpm_qa
        self.assertEqual(self.pkgs._get_installed_packages(), [
            dict(name='nagios-plugins', version='2.3.3', release='2.el7'),
            dict(name='nagios-plugins-file_age',
                 version='2.3.3',
                 release='2.el7'),
            dict(name='nagios-plugins-argo',
                 version='0.1.13',
                 release='20200901060701.5869b94.el7'),
            dict(name='nagios-plugins-fedcloud',
                 version='0.5.2',
                 release='20200511071632.05e2501.el7'),
            dict(name='nagios-plugins-igtf',
                 version='1.4.0',
                 release='20200713050846.f6ca58d.el7'),
            dict(name='nagios-plugins-dummy', version='2.3.3',
                 release='2.el7'),
            dict(name='nagios-common', version='4.4.5', release='7.el7'),
            dict(name='nagios-plugins-perl', version='2.3.3', release='2.el7'),
            dict(name='nagios-plugins-http', version='2.3.3', release='2.el7')
        ])

    @mock.patch('argo_poem_tools.packages.Packages._get_available_packages')
    @mock.patch('argo_poem_tools.packages.Packages._get_installed_packages')
    def test_get_analyzed_packages_all_ok(self, mock_rpmdb, mock_yumdb):
        mock_rpmdb.return_value = [
            dict(name='nagios-plugins-fedcloud',
                 version='0.4.0',
                 release='20190925233153.c3b9fdd.el7'),
            dict(name='nagios-plugins-igtf', version='1.5.0', release='3.el7'),
            dict(name='nagios-plugins-globus',
                 version='0.1.5',
                 release='20200713050450.eb1e7d8.el7'),
            dict(name='nagios-plugins-argo',
                 version='0.1.12',
                 release='20200401115402.f599b1b.el7')
        ]
        mock_yumdb.return_value = [
            dict(name='nagios-plugins-fedcloud',
                 version='0.5.0',
                 release='20191003144427.7acfd49.el7'),
            dict(name='nagios-plugins-fedcloud',
                 version='0.4.0',
                 release='20190925233153.c3b9fdd.el7'),
            dict(name='nagios-plugins-igtf', version='1.5.0', release='3.el7'),
            dict(name='nagios-plugins-igtf',
                 version='1.4.0',
                 release='20200713050846.f6ca58d.el7'),
            dict(name='nagios-plugins-globus',
                 version='0.1.5',
                 release='20200713050450.eb1e7d8.el7'),
            dict(name='nagios-plugins-http', version='2.3.3', release='1.el7'),
            dict(name='nagios-plugins-argo',
                 version='0.1.12',
                 release='20200716071827.5b8b5d6.el7')
        ]
        install, upgrade, downgrade, diff_ver, not_found = self.pkgs._get()
        self.assertEqual(install, [('nagios-plugins-http', )])
        self.assertEqual(
            set(upgrade), {(('nagios-plugins-fedcloud', '0.4.0'),
                            ('nagios-plugins-fedcloud', '0.5.0')),
                           (('nagios-plugins-argo', '0.1.12'), )})
        self.assertEqual(downgrade, [(('nagios-plugins-igtf', '1.5.0'),
                                      ('nagios-plugins-igtf', '1.4.0'))])
        self.assertEqual(diff_ver, [])
        self.assertEqual(not_found, [])

    @mock.patch('argo_poem_tools.packages.Packages._get_available_packages')
    @mock.patch('argo_poem_tools.packages.Packages._get_installed_packages')
    def test_get_analyzed_packages_wrong_version_and_not_found(
            self, mock_rpmdb, mock_yumdb):
        mock_rpmdb.return_value = [
            dict(name='nagios-plugins-fedcloud',
                 version='0.4.0',
                 release='20190925233153.c3b9fdd.el7'),
            dict(name='nagios-plugins-igtf', version='1.5.0', release='1.el7'),
            dict(name='nagios-plugins-http', version='2.3.2', release='2.el7')
        ]
        mock_yumdb.return_value = [
            dict(name='nagios-plugins-fedcloud',
                 version='0.5.0',
                 release='20191003144427.7acfd49.el7'),
            dict(name='nagios-plugins-fedcloud',
                 version='0.4.0',
                 release='20190925233153.c3b9fdd.el7'),
            dict(name='nagios-plugins-igtf', version='1.5.0', release='1.el7'),
            dict(name='nagios-plugins-igtf', version='1.4.0', release='3.el7'),
            dict(name='nagios-plugins-globus',
                 version='0.1.6',
                 release='20200713050450.eb1e7d8.el7'),
            dict(name='nagios-plugins-http', version='2.3.3', release='1.el7')
        ]
        install, upgrade, downgrade, diff_ver, not_found = self.pkgs._get()
        self.assertEqual(install, [])
        self.assertEqual(
            set(upgrade), {(('nagios-plugins-fedcloud', '0.4.0'),
                            ('nagios-plugins-fedcloud', '0.5.0')),
                           (('nagios-plugins-http', ), )})
        self.assertEqual(downgrade, [(('nagios-plugins-igtf', '1.5.0'),
                                      ('nagios-plugins-igtf', '1.4.0'))])
        self.assertEqual(diff_ver, ['nagios-plugins-globus-0.1.5'])
        self.assertEqual(not_found, ['nagios-plugins-argo-0.1.12'])

    @mock.patch('argo_poem_tools.packages.subprocess.check_call')
    @mock.patch('argo_poem_tools.packages.Packages._get_available_packages')
    @mock.patch('argo_poem_tools.packages.Packages._get_installed_packages')
    def test_get_analyzed_packages_if_marked_for_upgrade_and_same_version_avail(
            self, mock_rpmdb, mock_yumdb, mock_sp):
        mock_rpmdb.return_value = [
            dict(name='nagios-plugins-fedcloud',
                 version='0.4.0',
                 release='20190925233153.c3b9fdd.el7'),
            dict(name='nagios-plugins-igtf', version='1.5.0', release='3.el7'),
            dict(name='nagios-plugins-globus',
                 version='0.1.5',
                 release='20200713050450.eb1e7d8.el7'),
            dict(name='nagios-plugins-argo',
                 version='0.1.12',
                 release='20200401115402.f99b1b.el7')
        ]
        mock_yumdb.return_value = [
            dict(name='nagios-plugins-fedcloud',
                 version='0.4.0',
                 release='20190925233153.c3b9fdd.el7'),
            dict(name='nagios-plugins-igtf', version='1.5.0', release='3.el7'),
            dict(name='nagios-plugins-igtf',
                 version='1.4.0',
                 release='20200713050846.f6ca58d.el7'),
            dict(name='nagios-plugins-globus',
                 version='0.1.5',
                 release='20200713050450.eb1e7d8.el7'),
            dict(name='nagios-plugins-http', version='2.3.3', release='1.el7'),
            dict(name='nagios-plugins-argo',
                 version='0.1.12',
                 release='20200401115402.f99b1b.el7'),
            dict(name='nagios-plugins-argo',
                 version='0.1.12',
                 release='20200716071827.5b8b5d6.el7')
        ]
        install, upgrade, downgrade, diff_ver, not_found = self.pkgs._get()
        self.assertFalse(mock_sp.called)
        self.assertEqual(install, [('nagios-plugins-http', )])
        self.assertEqual(upgrade, [(('nagios-plugins-argo', '0.1.12'), )])
        self.assertEqual(downgrade, [(('nagios-plugins-igtf', '1.5.0'),
                                      ('nagios-plugins-igtf', '1.4.0'))])
        self.assertEqual(diff_ver, ['nagios-plugins-fedcloud-0.5.0'])
        self.assertEqual(not_found, [])

    @mock.patch('argo_poem_tools.packages.subprocess.check_call')
    @mock.patch('argo_poem_tools.packages.Packages._get_available_packages')
    @mock.patch('argo_poem_tools.packages.Packages._get_installed_packages')
    def test_get_packages_if_installed_and_wrong_version_available(
            self, mock_rpmdb, mock_yumdb, mock_sp):
        mock_rpmdb.return_value = [
            dict(name='nagios-plugins-fedcloud',
                 version='0.4.0',
                 release='20190925233153.c3b9fdd.el7'),
            dict(name='nagios-plugins-igtf', version='1.5.0', release='1.el7'),
            dict(name='nagios-plugins-http', version='2.0.0', release='2.el7')
        ]
        mock_yumdb.return_value = [
            dict(name='nagios-plugins-fedcloud',
                 version='0.5.0',
                 release='20191003144427.7acfd49.el7'),
            dict(name='nagios-plugins-fedcloud',
                 version='0.4.0',
                 release='20190925233153.c3b9fdd.el7'),
            dict(name='nagios-plugins-igtf', version='1.5.0', release='1.el7'),
            dict(name='nagios-plugins-igtf', version='1.4.0', release='3.el7'),
            dict(name='nagios-plugins-globus',
                 version='0.1.6',
                 release='20200713050450.eb1e7d8.el7'),
            dict(name='nagios-plugins-http', version='2.3.3', release='1.el7'),
            dict(name='nagios-plugins-argo',
                 version='0.1.12',
                 release='20200716071827.5b8b5d6.el7')
        ]
        install, upgrade, downgrade, diff_ver, not_found = self.pkgs._get()
        self.assertFalse(mock_sp.called)
        self.assertEqual(install, [('nagios-plugins-argo', '0.1.12')])
        self.assertEqual(
            set(upgrade), {(('nagios-plugins-fedcloud', '0.4.0'),
                            ('nagios-plugins-fedcloud', '0.5.0')),
                           (('nagios-plugins-http', ), )})
        self.assertEqual(downgrade, [(('nagios-plugins-igtf', '1.5.0'),
                                      ('nagios-plugins-igtf', '1.4.0'))])
        self.assertEqual(diff_ver, ['nagios-plugins-globus-0.1.5'])
        self.assertEqual(not_found, [])

    @mock.patch('argo_poem_tools.packages.Packages._lock_versions')
    @mock.patch('argo_poem_tools.packages.subprocess.check_call')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_install_packages(self, mock_get, mock_check_call, mock_lock):
        mock_get.return_value = ([('nagios-plugins-http', )], [(
            ('nagios-plugins-fedcloud', '0.4.0'),
            ('nagios-plugins-fedcloud', '0.5.0'),
        ), (('nagios-plugins-argo', '0.1.12'), )],
                                 [(('nagios-plugins-igtf', '1.5.0'),
                                   ('nagios-plugins-igtf', '1.4.0'))], [], [])
        mock_check_call.side_effect = mock_func
        mock_lock.side_effect = mock_func
        info, warn = self.pkgs.install()
        self.assertEqual(mock_check_call.call_count, 4)
        mock_check_call.assert_has_calls([
            mock.call(
                ['yum', '-y', 'install', 'nagios-plugins-fedcloud-0.5.0']),
            mock.call(['yum', '-y', 'downgrade', 'nagios-plugins-igtf-1.4.0']),
            mock.call(['yum', '-y', 'install', 'nagios-plugins-http']),
            mock.call(['yum', '-y', 'install', 'nagios-plugins-argo-0.1.12']),
        ],
                                         any_order=True)
        self.assertEqual(mock_lock.call_count, 1)
        self.assertEqual(info, [
            'Packages installed: nagios-plugins-http', 'Packages upgraded: '
            'nagios-plugins-fedcloud-0.4.0 -> '
            'nagios-plugins-fedcloud-0.5.0; nagios-plugins-argo-0.1.12',
            'Packages downgraded: '
            'nagios-plugins-igtf-1.5.0 -> nagios-plugins-igtf-1.4.0'
        ])
        self.assertEqual(warn, [])

    @mock.patch('argo_poem_tools.packages.Packages._lock_versions')
    @mock.patch('argo_poem_tools.packages.subprocess.check_call')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_install_packages_if_installed_and_wrong_version_available(
            self, mock_get, mock_check_call, mock_lock):
        mock_get.return_value = ([('nagios-plugins-argo', '0.1.12')], [(
            ('nagios-plugins-fedcloud', '0.4.0'),
            ('nagios-plugins-fedcloud', '0.5.0'),
        ), (('nagios-plugins-http', ), )], [
            (('nagios-plugins-igtf', '1.5.0'), ('nagios-plugins-igtf',
                                                '1.4.0'))
        ], ['nagios-plugins-globus-0.1.5'], [])
        mock_check_call.side_effect = mock_func
        mock_lock.side_effect = mock_func
        info, warn = self.pkgs.install()
        self.assertEqual(mock_check_call.call_count, 4)
        self.assertEqual(mock_lock.call_count, 1)
        mock_check_call.assert_has_calls([
            mock.call(
                ['yum', '-y', 'install', 'nagios-plugins-fedcloud-0.5.0']),
            mock.call(['yum', '-y', 'downgrade', 'nagios-plugins-igtf-1.4.0']),
            mock.call(['yum', '-y', 'install', 'nagios-plugins-http']),
            mock.call(['yum', '-y', 'install', 'nagios-plugins-argo-0.1.12'])
        ],
                                         any_order=True)
        self.assertEqual(info, [
            'Packages installed: nagios-plugins-argo-0.1.12',
            'Packages upgraded: '
            'nagios-plugins-fedcloud-0.4.0 -> nagios-plugins-fedcloud-'
            '0.5.0; nagios-plugins-http',
            'Packages downgraded: '
            'nagios-plugins-igtf-1.5.0 -> nagios-plugins-igtf-1.4.0',
        ])
        self.assertEqual(warn, [
            'Packages not found with requested version: '
            'nagios-plugins-globus-0.1.5'
        ])

    @mock.patch('argo_poem_tools.packages.Packages._lock_versions')
    @mock.patch('argo_poem_tools.packages.subprocess.check_call')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_install_if_packages_not_found(self, mock_get, mock_check_call,
                                           mock_lock):
        mock_get.return_value = ([
            ('nagios-plugins-igtf', '1.4.0')
        ], [], [], ['nagios-plugins-fedcloud-0.5.0'], [
            'nagios-plugins-globus-0.1.5', 'nagios-plugins-argo-0.1.12',
            'nagios-plugins-http'
        ])
        mock_check_call.side_effect = mock_func
        mock_lock.side_effect = mock_func
        info, warn = self.pkgs.install()
        self.assertEqual(mock_check_call.call_count, 1)
        self.assertEqual(mock_lock.call_count, 1)
        mock_check_call.assert_has_calls([
            mock.call(['yum', '-y', 'install', 'nagios-plugins-igtf-1.4.0']),
        ],
                                         any_order=True)
        self.assertEqual(info,
                         ['Packages installed: nagios-plugins-igtf-1.4.0'])
        self.assertEqual(warn, [
            'Packages not found with requested version: '
            'nagios-plugins-fedcloud-0.5.0', 'Packages not found: '
            'nagios-plugins-globus-0.1.5; nagios-plugins-argo-0.1.12; '
            'nagios-plugins-http'
        ])

    @mock.patch('argo_poem_tools.packages.Packages._lock_versions')
    @mock.patch('argo_poem_tools.packages.subprocess.check_call')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_install_if_packages_marked_for_upgrade_and_same_version_avail(
            self, mock_get, mock_check_call, mock_lock):
        mock_get.return_value = ([('nagios-plugins-http', )], [
            (('nagios-plugins-argo', '0.1.12'), )
        ], [(('nagios-plugins-igtf', '1.5.0'), ('nagios-plugins-igtf',
                                                '1.4.0'))],
                                 ['nagios-plugins-fedcloud-0.5.0'], [])
        mock_check_call.side_effect = mock_func
        mock_lock.side_effect = mock_func
        info, warn = self.pkgs.install()
        self.assertEqual(mock_check_call.call_count, 3)
        mock_check_call.assert_has_calls([
            mock.call(['yum', '-y', 'install', 'nagios-plugins-http']),
            mock.call(['yum', '-y', 'downgrade', 'nagios-plugins-igtf-1.4.0']),
            mock.call(['yum', '-y', 'install', 'nagios-plugins-argo-0.1.12'])
        ],
                                         any_order=True)
        self.assertEqual(mock_lock.call_count, 1)
        self.assertEqual(info, [
            'Packages installed: nagios-plugins-http',
            'Packages upgraded: nagios-plugins-argo-0.1.12',
            'Packages downgraded: '
            'nagios-plugins-igtf-1.5.0 -> nagios-plugins-igtf-1.4.0'
        ])
        self.assertEqual(warn, [
            'Packages not found with requested version: '
            'nagios-plugins-fedcloud-0.5.0'
        ])

    @mock.patch('argo_poem_tools.packages.Packages._failsafe_lock_versions')
    @mock.patch('argo_poem_tools.packages.subprocess.check_call')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_install_lock_versions_if_exception(self, mock_get,
                                                mock_check_call, mock_lock):
        self.pkgs.initially_locked_versions = [
            'nagios-plugins-argo', 'nagios-plugins-fedcloud'
        ]
        mock_get.side_effect = mock_func_exception
        mock_check_call.side_effect = mock_func
        mock_lock.side_effect = mock_func
        with self.assertRaises(PackageException):
            self.pkgs.install()
        self.assertFalse(mock_check_call.called)
        self.assertEqual(mock_lock.call_count, 1)

    @mock.patch('argo_poem_tools.packages.Packages._lock_versions')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_no_op_run(self, mock_get, mock_lock):
        self.pkgs.versions_unlocked = True
        self.pkgs.locked_versions = [
            'nagios-plugins-argo', 'nagios-plugins-igtf'
        ]
        mock_get.return_value = ([('nagios-plugins-http', )], [(
            ('nagios-plugins-fedcloud', '0.4.0'),
            ('nagios-plugins-fedcloud', '0.5.0'),
        ), (('nagios-plugins-argo', '0.1.12'), )],
                                 [(('nagios-plugins-igtf', '1.5.0'),
                                   ('nagios-plugins-igtf', '1.4.0'))], [], [])
        mock_lock.side_effect = mock_func
        info, warn = self.pkgs.no_op()
        self.assertEqual(mock_lock.call_count, 1)
        self.assertEqual(info, [
            'Packages to be installed: nagios-plugins-http',
            'Packages to be upgraded: '
            'nagios-plugins-fedcloud-0.4.0 -> '
            'nagios-plugins-fedcloud-0.5.0; nagios-plugins-argo-0.1.12',
            'Packages to be downgraded: '
            'nagios-plugins-igtf-1.5.0 -> nagios-plugins-igtf-1.4.0'
        ])
        self.assertEqual(warn, [])

    @mock.patch('argo_poem_tools.packages.Packages._lock_versions')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_no_op_if_installed_and_wrong_version_available(
            self, mock_get, mock_lock):
        self.pkgs.versions_unlocked = True
        self.pkgs.locked_versions = ['nagios-plugins-fedcloud']
        mock_get.return_value = ([('nagios-plugins-argo', '0.1.12')], [(
            ('nagios-plugins-fedcloud', '0.4.0'),
            ('nagios-plugins-fedcloud', '0.5.0'),
        ), (('nagios-plugins-http', ), )], [
            (('nagios-plugins-igtf', '1.5.0'), ('nagios-plugins-igtf',
                                                '1.4.0'))
        ], ['nagios-plugins-globus-0.1.5'], [])
        info, warn = self.pkgs.no_op()
        self.assertEqual(mock_lock.call_count, 1)
        self.assertEqual(info, [
            'Packages to be installed: nagios-plugins-argo-0.1.12',
            'Packages to be upgraded: '
            'nagios-plugins-fedcloud-0.4.0 -> nagios-plugins-fedcloud-'
            '0.5.0; nagios-plugins-http',
            'Packages to be downgraded: '
            'nagios-plugins-igtf-1.5.0 -> nagios-plugins-igtf-1.4.0',
        ])
        self.assertEqual(warn, [
            'Packages not found with requested version: '
            'nagios-plugins-globus-0.1.5'
        ])

    @mock.patch('argo_poem_tools.packages.Packages._lock_versions')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_no_op_if_packages_not_found(self, mock_get, mock_lock):
        mock_get.return_value = ([
            ('nagios-plugins-igtf', '1.4.0')
        ], [], [], ['nagios-plugins-fedcloud-0.5.0'], [
            'nagios-plugins-globus-0.1.5', 'nagios-plugins-argo-0.1.12',
            'nagios-plugins-http'
        ])
        mock_lock.side_effect = mock_func
        info, warn = self.pkgs.no_op()
        self.assertEqual(mock_lock.call_count, 1)
        self.assertEqual(
            info, ['Packages to be installed: nagios-plugins-igtf-1.4.0'])
        self.assertEqual(warn, [
            'Packages not found with requested version: '
            'nagios-plugins-fedcloud-0.5.0', 'Packages not found: '
            'nagios-plugins-globus-0.1.5; nagios-plugins-argo-0.1.12; '
            'nagios-plugins-http'
        ])

    @mock.patch('argo_poem_tools.packages.Packages._lock_versions')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_no_op_if_packages_marked_for_upgrade_and_same_version_avail(
            self, mock_get, mock_lock):
        mock_get.return_value = ([('nagios-plugins-http', )], [
            (('nagios-plugins-argo', '0.1.12'), )
        ], [(('nagios-plugins-igtf', '1.5.0'), ('nagios-plugins-igtf',
                                                '1.4.0'))],
                                 ['nagios-plugins-fedcloud-0.5.0'], [])
        mock_lock.side_effect = mock_func
        info, warn = self.pkgs.no_op()
        self.assertEqual(mock_lock.call_count, 1)
        self.assertEqual(info, [
            'Packages to be installed: nagios-plugins-http',
            'Packages to be upgraded: nagios-plugins-argo-0.1.12',
            'Packages to be downgraded: '
            'nagios-plugins-igtf-1.5.0 -> nagios-plugins-igtf-1.4.0'
        ])
        self.assertEqual(warn, [
            'Packages not found with requested version: '
            'nagios-plugins-fedcloud-0.5.0'
        ])

    @mock.patch('argo_poem_tools.packages.Packages._failsafe_lock_versions')
    @mock.patch('argo_poem_tools.packages.subprocess.check_call')
    @mock.patch('argo_poem_tools.packages.Packages._get')
    def test_no_op_lock_versions_if_exception(self, mock_get, mock_check_call,
                                              mock_lock):
        self.pkgs.initially_locked_versions = [
            'nagios-plugins-argo', 'nagios-plugins-fedcloud'
        ]
        mock_get.side_effect = mock_func_exception
        mock_check_call.side_effect = mock_func
        mock_lock.side_effect = mock_func
        with self.assertRaises(PackageException):
            self.pkgs.no_op()
        self.assertFalse(mock_check_call.called)
        self.assertEqual(mock_lock.call_count, 1)

    @mock.patch('argo_poem_tools.packages.subprocess.call')
    @mock.patch('argo_poem_tools.packages.subprocess.check_output')
    def test_lock_unlocked_versions(self, mock_subprocess, mock_call):
        mock_subprocess.side_effect = [mock_yum_versionlock_list, mock_rpm_qa]
        mock_call.side_effect = mock_func
        warn = self.pkgs._lock_versions()
        self.assertFalse(warn)
        self.assertEqual(mock_call.call_count, 1)
        mock_call.assert_has_calls([
            mock.call(['yum', 'versionlock', 'add', 'nagios-plugins-igtf'],
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE)
        ],
                                   any_order=True)

    @mock.patch('argo_poem_tools.packages.subprocess.call')
    @mock.patch('argo_poem_tools.packages.subprocess.check_output')
    def test_lock_unlocked_versions_if_package_not_installed(
            self, mock_subprocess, mock_call):
        mock_rpm_qa1 = \
            """
            nagios-plugins-2.3.3-2.el7.x86_64
            nagios-plugins-file_age-2.3.3-2.el7.x86_64
            nagios-plugins-argo-0.1.13-20200901060701.5869b94.el7.noarch
            nagios-plugins-fedcloud-0.5.2-20200511071632.05e2501.el7.noarch
            nagios-plugins-dummy-2.3.3-2.el7.x86_64
            nagios-common-4.4.5-7.el7.x86_64
            nagios-plugins-perl-2.3.3-2.el7.x86_64
            nagios-plugins-http-2.3.3-2.el7.x86_64
    
            """.encode('utf-8')
        mock_subprocess.side_effect = [mock_yum_versionlock_list, mock_rpm_qa1]
        mock_call.side_effect = mock_func
        warn = self.pkgs._lock_versions()
        self.assertFalse(warn)
        self.assertEqual(mock_call.call_count, 0)

    @mock.patch('argo_poem_tools.packages.subprocess.call')
    @mock.patch('argo_poem_tools.packages.subprocess.check_output')
    def test_lock_unlocked_versions_exception(self, mock_subprocess,
                                              mock_call):
        mock_subprocess.side_effect = [mock_yum_versionlock_list, mock_rpm_qa]
        mock_call.side_effect = mock_func_exception
        warn = self.pkgs._lock_versions()
        self.assertEqual(mock_call.call_count, 1)
        mock_call.assert_has_calls([
            mock.call(['yum', 'versionlock', 'add', 'nagios-plugins-igtf'],
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE)
        ],
                                   any_order=True)
        self.assertEqual(warn, 'Packages not locked: nagios-plugins-igtf')
class PackageTests(unittest.TestCase):
    def setUp(self):
        self.pkgs = Packages(data)

    def test_get_package_list(self):
        self.assertEqual(self.pkgs.list_of_packages(),
                         [('nordugrid-arc-nagios-plugins', ),
                          ('nagios-plugins-fedcloud', '0.5.0'),
                          ('nagios-plugins-igtf', '1.4.0'),
                          ('nagios-plugins-globus', '0.1.5')])

    @mock.patch('yum.YumBase.pkgSack')
    @mock.patch('yum.YumBase.rpmdb')
    def test_get_packages(self, mock_yumbase1, mock_yumbase2):
        mock1 = mock.Mock(version='0.5.0')
        mock2 = mock.Mock(version='0.4.0')
        mock3 = mock.Mock(version='1.5.0')
        mock4 = mock.Mock(version='1.4.0')
        mock5 = mock.Mock(version='0.1.5')
        mock6 = mock.Mock(version='2.0.0')
        mock1.name = 'nagios-plugins-fedcloud'
        mock2.name = 'nagios-plugins-fedcloud'
        mock3.name = 'nagios-plugins-igtf'
        mock4.name = 'nagios-plugins-igtf'
        mock5.name = 'nagios-plugins-globus'
        mock6.name = 'nordugrid-arc-nagios-plugins'
        mock_yumbase1.returnPackages.return_value = [mock2, mock3]
        mock_yumbase2.returnPackages.return_value = [
            mock1, mock2, mock3, mock4, mock5, mock6
        ]

        install, downgrade = self.pkgs.get_packages()

        self.assertEqual(install, [
            'nordugrid-arc-nagios-plugins', 'nagios-plugins-fedcloud-0.5.0',
            'nagios-plugins-globus-0.1.5'
        ])
        self.assertEqual(downgrade, ['nagios-plugins-igtf-1.4.0'])

    @mock.patch('yum.YumBase.pkgSack')
    @mock.patch('yum.YumBase.rpmdb')
    def test_get_packages_if_installed_and_wrong_version_available(
            self, mock_yumbase1, mock_yumbase2):
        mock1 = mock.Mock(version='0.5.0')
        mock2 = mock.Mock(version='0.4.0')
        mock3 = mock.Mock(version='1.5.0')
        mock4 = mock.Mock(version='1.4.0')
        mock5 = mock.Mock(version='0.1.5')
        mock6 = mock.Mock(version='2.0.1')
        mock7 = mock.Mock(version='1.9.0')
        mock1.name = 'nagios-plugins-fedcloud'
        mock2.name = 'nagios-plugins-fedcloud'
        mock3.name = 'nagios-plugins-igtf'
        mock4.name = 'nagios-plugins-igtf'
        mock5.name = 'nagios-plugins-globus'
        mock6.name = 'nordugrid-arc-nagios-plugins'
        mock7.name = 'nordugrid-arc-nagios-plugins'
        mock_yumbase1.returnPackages.return_value = [mock2, mock3, mock7]
        mock_yumbase2.returnPackages.return_value = [
            mock1, mock2, mock3, mock4, mock5, mock6
        ]

        install, downgrade = self.pkgs.get_packages()

        self.assertEqual(
            install,
            ['nagios-plugins-fedcloud-0.5.0', 'nagios-plugins-globus-0.1.5'])
        self.assertEqual(downgrade, ['nagios-plugins-igtf-1.4.0'])

    @mock.patch('yum.YumBase.pkgSack')
    def test_exact_packages_not_found(self, mock_yumbase):
        mock1 = mock.Mock(version='2.0.0')
        mock2 = mock.Mock(version='0.6.0')
        mock3 = mock.Mock(version='1.4.0')
        mock1.name = 'nordugrid-arc-nagios-plugins'
        mock2.name = 'nagios-plugins-fedcloud'
        mock3.name = 'nagios-plugins-igtf'
        mock_yumbase.returnPackages.return_value = [mock1, mock2, mock3]

        self.assertEqual(self.pkgs.exact_packages_not_found(),
                         [('nagios-plugins-fedcloud', '0.5.0'),
                          ('nagios-plugins-globus', '0.1.5')])

    @mock.patch('yum.YumBase.pkgSack')
    def test_packages_not_found(self, mock_yumbase):
        mock1 = mock.Mock(version='2.0.0')
        mock2 = mock.Mock(version='0.6.0')
        mock3 = mock.Mock(version='1.4.0')
        mock1.name = 'nordugrid-arc-nagios-plugins'
        mock2.name = 'nagios-plugins-fedcloud'
        mock3.name = 'nagios-plugins-igtf'
        mock_yumbase.returnPackages.return_value = [mock1, mock2, mock3]

        self.assertEqual(self.pkgs.packages_not_found(),
                         [('nagios-plugins-globus', '0.1.5')])

    @mock.patch('yum.YumBase.pkgSack')
    def test_get_packages_not_found(self, mock_yumbase):
        mock1 = mock.Mock(version='0.6.0')
        mock2 = mock.Mock(version='1.4.0')
        mock1.name = 'nagios-plugins-fedcloud'
        mock2.name = 'nagios-plugins-igtf'
        mock_yumbase.returnPackages.return_value = [mock1, mock2]

        self.assertEqual(
            self.pkgs.get_packages_not_found(),
            ['nordugrid-arc-nagios-plugins', 'nagios-plugins-globus-0.1.5'])

    @mock.patch('yum.YumBase.pkgSack')
    def test_packages_found_with_different_version(self, mock_yumbase):
        mock1 = mock.Mock(version='2.0.0')
        mock2 = mock.Mock(version='0.5.0')
        mock3 = mock.Mock(version='1.5.0')
        mock1.name = 'nordugrid-arc-nagios-plugins'
        mock2.name = 'nagios-plugins-fedcloud'
        mock3.name = 'nagios-plugins-igtf'
        mock_yumbase.returnPackages.return_value = [mock1, mock2, mock3]

        self.assertEqual(self.pkgs.packages_found_with_different_version(),
                         [('nagios-plugins-igtf', '1.5.0')])

    @mock.patch('yum.YumBase.pkgSack')
    def test_get_packages_installed_with_different_version(self, mock_yumbase):
        mock1 = mock.Mock(version='2.0.0')
        mock2 = mock.Mock(version='0.5.0')
        mock3 = mock.Mock(version='1.5.0')
        mock1.name = 'nordugrid-arc-nagios-plugins'
        mock2.name = 'nagios-plugins-fedcloud'
        mock3.name = 'nagios-plugins-igtf'
        mock_yumbase.returnPackages.return_value = [mock1, mock2, mock3]

        self.assertEqual(
            self.pkgs.get_packages_installed_with_different_version(),
            ['nagios-plugins-igtf-1.4.0 -> nagios-plugins-igtf-1.5.0'])

    @mock.patch('yum.YumBase.pkgSack')
    def test_get_packages_installed_with_version_as_requested(
            self, mock_yumbase):
        mock1 = mock.Mock(version='2.0.0')
        mock2 = mock.Mock(version='0.5.0')
        mock3 = mock.Mock(version='1.5.0')
        mock1.name = 'nordugrid-arc-nagios-plugins'
        mock2.name = 'nagios-plugins-fedcloud'
        mock3.name = 'nagios-plugins-igtf'
        mock_yumbase.returnPackages.return_value = [mock1, mock2, mock3]

        self.assertEqual(
            self.pkgs.get_packages_installed_with_versions_as_requested([
                'nordugrid-arc-nagios-plugins',
                'nagios-plugins-fedcloud-0.5.0', 'nagios-plugins-igtf'
            ]),
            ['nordugrid-arc-nagios-plugins', 'nagios-plugins-fedcloud-0.5.0'])