Example #1
0
    def __init__(self, context):
        super(RpmStatusRenderer, self).__init__(context)

        self.publish_steps_renderer = PublishStepStatusRenderer(context)

        # Sync Steps
        self.metadata_last_state = constants.STATE_NOT_STARTED
        self.download_last_state = constants.STATE_NOT_STARTED
        self.distribution_sync_last_state = constants.STATE_NOT_STARTED
        self.errata_last_state = constants.STATE_NOT_STARTED
        self.comps_last_state = constants.STATE_NOT_STARTED

        # Publish Steps
        self.publish_steps_last_state = dict.fromkeys(
            constants.PUBLISH_STEPS, constants.STATE_NOT_STARTED)

        self.distribution_publish_last_state = constants.STATE_NOT_STARTED
        self.generate_metadata_last_state = constants.STATE_NOT_STARTED
        self.publish_http_last_state = constants.STATE_NOT_STARTED
        self.publish_https_last_state = constants.STATE_NOT_STARTED

        # UI Widgets
        self.metadata_spinner = self.prompt.create_spinner()
        self.download_bar = self.prompt.create_progress_bar()
        self.distribution_sync_bar = self.prompt.create_progress_bar()
        self.errata_spinner = self.prompt.create_spinner()
        self.comps_spinner = self.prompt.create_spinner()

        self.packages_bar = self.prompt.create_progress_bar()
        self.distribution_publish_bar = self.prompt.create_progress_bar()
        self.generate_metadata_spinner = self.prompt.create_spinner()
        self.publish_http_spinner = self.prompt.create_spinner()
        self.publish_https_spinner = self.prompt.create_spinner()
Example #2
0
 def setUp(self):
     super(TestRefreshContentSourcesCommand, self).setUp()
     self.context = MagicMock(
         config={'output': {
             'poll_frequency_in_seconds': 1
         }})
     self.prompt = Mock()
     self.context.prompt = self.prompt
     self.renderer = PublishStepStatusRenderer(self.context)
     self.command = RefreshContentSourcesCommand(self.context,
                                                 self.renderer)
     step_details = {
         'source_id': '1',
         'succeeded': None,
         'url': 'mock-url',
         'added_count': '2',
         'deleted_count': '0',
         'errors': []
     }
     self.step = {
         reporting_constants.PROGRESS_STEP_TYPE_KEY: u'foo_step',
         reporting_constants.PROGRESS_STEP_UUID: u'abcde',
         reporting_constants.PROGRESS_DESCRIPTION_KEY: u'foo description',
         reporting_constants.PROGRESS_DETAILS_KEY: [step_details],
         reporting_constants.PROGRESS_STATE_KEY:
         reporting_constants.STATE_NOT_STARTED,
         reporting_constants.PROGRESS_ITEMS_TOTAL_KEY: 1,
         reporting_constants.PROGRESS_NUM_PROCESSED_KEY: 0,
         reporting_constants.PROGRESS_ERROR_DETAILS_KEY: []
     }
Example #3
0
    def __init__(self, context):
        super(RpmStatusRenderer, self).__init__(context)

        self.publish_steps_renderer = PublishStepStatusRenderer(context)

        # Sync Steps
        self.metadata_last_state = constants.STATE_NOT_STARTED
        self.download_last_state = constants.STATE_NOT_STARTED
        self.distribution_sync_last_state = constants.STATE_NOT_STARTED
        self.errata_last_state = constants.STATE_NOT_STARTED
        self.comps_last_state = constants.STATE_NOT_STARTED

        # Publish Steps
        self.publish_steps_last_state = dict.fromkeys(constants.PUBLISH_STEPS,
                                                      constants.STATE_NOT_STARTED)

        self.distribution_publish_last_state = constants.STATE_NOT_STARTED
        self.generate_metadata_last_state = constants.STATE_NOT_STARTED
        self.publish_http_last_state = constants.STATE_NOT_STARTED
        self.publish_https_last_state = constants.STATE_NOT_STARTED

        # UI Widgets
        self.metadata_spinner = self.prompt.create_spinner()
        self.download_bar = self.prompt.create_progress_bar()
        self.distribution_sync_bar = self.prompt.create_progress_bar()
        self.errata_spinner = self.prompt.create_spinner()
        self.comps_spinner = self.prompt.create_spinner()

        self.packages_bar = self.prompt.create_progress_bar()
        self.distribution_publish_bar = self.prompt.create_progress_bar()
        self.generate_metadata_spinner = self.prompt.create_spinner()
        self.publish_http_spinner = self.prompt.create_spinner()
        self.publish_https_spinner = self.prompt.create_spinner()
Example #4
0
    def __init__(self, context):
        super(PackageStatusRenderer, self).__init__(context)

        self.publish_steps_renderer = PublishStepStatusRenderer(context)

        # Publish Steps
        self.publish_steps_last_state = dict.fromkeys(
            constants.PUBLISH_STEPS, constants.STATE_NOT_STARTED)

        self.publish_http_last_state = constants.STATE_NOT_STARTED
        self.publish_https_last_state = constants.STATE_NOT_STARTED

        # UI Widgets
        self.packages_bar = self.prompt.create_progress_bar()
        self.publish_http_spinner = self.prompt.create_spinner()
        self.publish_https_spinner = self.prompt.create_spinner()
Example #5
0
def initialize(context):
    structure.ensure_repo_structure(context.cli)
    upload_manager = _upload_manager(context)

    repo_section = structure.repo_section(context.cli)
    repo_section.add_command(repo_create_update.PkgRepoCreateCommand(context))
    repo_section.add_command(repo_create_update.PkgRepoUpdateCommand(context))
    repo_section.add_command(cudl.DeleteRepositoryCommand(context))
    repo_section.add_command(repo_list.RepoListCommand(context))
    repo_section.add_command(
        RepoSearchCommand(context, constants.REPO_NOTE_PKG))

    copy_section = structure.repo_copy_section(context.cli)
    copy_section.add_command(copy_commands.MsiCopyCommand(context))
    copy_section.add_command(copy_commands.MsmCopyCommand(context))
    copy_section.add_command(copy_commands.AllCopyCommand(context))

    remove_section = structure.repo_remove_section(context.cli)
    remove_section.add_command(remove.MsiRemoveCommand(context))
    remove_section.add_command(remove.MsmRemoveCommand(context))

    contents_section = structure.repo_contents_section(context.cli)
    contents_section.add_command(contents.SearchMsiCommand(context))
    contents_section.add_command(contents.SearchMsmCommand(context))

    uploads_section = structure.repo_uploads_section(context.cli)
    for cls_ in [
            package.CreateMsiCommand, package.CreateMsmCommand,
            upload.ResumeCommand, upload.CancelCommand, upload.ListCommand
    ]:
        uploads_section.add_command(cls_(context, upload_manager))

    sync_section = structure.repo_sync_section(context.cli)
    renderer = status.PackageStatusRenderer(context)
    sync_section.add_command(
        sync_publish.RunSyncRepositoryCommand(context, renderer))
    sync_section.add_command(sync_publish.SyncStatusCommand(context, renderer))

    publish_section = structure.repo_publish_section(context.cli)
    renderer = PublishStepStatusRenderer(context)
    distributor_id = ids.TYPE_ID_DISTRIBUTOR_WIN
    publish_section.add_command(
        sync_publish.RunPublishRepositoryCommand(context, renderer,
                                                 distributor_id))
    publish_section.add_command(
        sync_publish.PublishStatusCommand(context, renderer))

    sync_schedules_section = structure.repo_sync_schedules_section(context.cli)
    sync_schedules_section.add_command(
        sync_schedules.PkgCreateScheduleCommand(context))
    sync_schedules_section.add_command(
        sync_schedules.PkgUpdateScheduleCommand(context))
    sync_schedules_section.add_command(
        sync_schedules.PkgDeleteScheduleCommand(context))
    sync_schedules_section.add_command(
        sync_schedules.PkgListScheduleCommand(context))

    sync_schedules_section.add_command(
        sync_schedules.PkgNextRunCommand(context))
Example #6
0
 def __init__(self, context):
     """
     :param context: The client context.
     :type context: pulp.client.extensions.core.ClientContext
     """
     super(SourcesSection, self).__init__(self.NAME, self.DESCRIPTION)
     self.add_command(ListCommand(context))
     renderer = PublishStepStatusRenderer(context)
     self.add_command(RefreshContentSourcesCommand(context, renderer))
Example #7
0
class PackageStatusRenderer(StatusRenderer):
    def __init__(self, context):
        super(PackageStatusRenderer, self).__init__(context)

        self.publish_steps_renderer = PublishStepStatusRenderer(context)

        # Publish Steps
        self.publish_steps_last_state = dict.fromkeys(
            constants.PUBLISH_STEPS,
            constants.STATE_NOT_STARTED)

        self.publish_http_last_state = constants.STATE_NOT_STARTED
        self.publish_https_last_state = constants.STATE_NOT_STARTED

        # UI Widgets
        self.packages_bar = self.prompt.create_progress_bar()
        self.publish_http_spinner = self.prompt.create_spinner()
        self.publish_https_spinner = self.prompt.create_spinner()

    def display_report(self, progress_report):
        """
        Displays the contents of the progress report to the user. This will
        aggregate the calls to render individual sections of the report.
        """

        # There's a small race condition where the task will indicate it's
        # begun running but the importer has yet to submit a progress report
        # (or it has yet to be saved into the task). This should be alleviated
        # by the if statements below.
        try:
            # Sync Steps
            if ids.TYPE_ID_IMPORTER_WIN in progress_report:
                pass

            # Publish Steps
            if ids.TYPE_ID_DISTRIBUTOR_WIN in progress_report:
                # Proxy to the standard renderer
                self.publish_steps_renderer.display_report(progress_report)

        except CancelException:
            self.prompt.render_failure_message(_('Operation canceled.'))
Example #8
0
class PackageStatusRenderer(StatusRenderer):
    def __init__(self, context):
        super(PackageStatusRenderer, self).__init__(context)

        self.publish_steps_renderer = PublishStepStatusRenderer(context)

        # Publish Steps
        self.publish_steps_last_state = dict.fromkeys(
            constants.PUBLISH_STEPS, constants.STATE_NOT_STARTED)

        self.publish_http_last_state = constants.STATE_NOT_STARTED
        self.publish_https_last_state = constants.STATE_NOT_STARTED

        # UI Widgets
        self.packages_bar = self.prompt.create_progress_bar()
        self.publish_http_spinner = self.prompt.create_spinner()
        self.publish_https_spinner = self.prompt.create_spinner()

    def display_report(self, progress_report):
        """
        Displays the contents of the progress report to the user. This will
        aggregate the calls to render individual sections of the report.
        """

        # There's a small race condition where the task will indicate it's
        # begun running but the importer has yet to submit a progress report
        # (or it has yet to be saved into the task). This should be alleviated
        # by the if statements below.
        try:
            # Sync Steps
            if ids.TYPE_ID_IMPORTER in progress_report:
                pass

            # Publish Steps
            if ids.TYPE_ID_DISTRIBUTOR in progress_report:
                # Proxy to the standard renderer
                self.publish_steps_renderer.display_report(progress_report)

        except CancelException:
            self.prompt.render_failure_message(_('Operation canceled.'))
Example #9
0
    def __init__(self, context):
        """
        @param context:
        @type  context: pulp.client.extensions.core.ClientContext
        """
        PulpCliSection.__init__(self, 'repo', _('list repositories and manage repo groups'))

        self.context = context
        self.prompt = context.prompt  # for easier access

        self.add_command(repo_commands.ListRepositoriesCommand(context, include_all_flag=False))
        self.add_command(DownloadRepositoryCommand(context, PublishStepStatusRenderer(context)))

        # Subsections
        self.add_subsection(RepoGroupSection(context))
        self.add_subsection(RepoHistorySection(context))
Example #10
0
    def __init__(self, context):
        super(PackageStatusRenderer, self).__init__(context)

        self.publish_steps_renderer = PublishStepStatusRenderer(context)

        # Publish Steps
        self.publish_steps_last_state = dict.fromkeys(
            constants.PUBLISH_STEPS,
            constants.STATE_NOT_STARTED)

        self.publish_http_last_state = constants.STATE_NOT_STARTED
        self.publish_https_last_state = constants.STATE_NOT_STARTED

        # UI Widgets
        self.packages_bar = self.prompt.create_progress_bar()
        self.publish_http_spinner = self.prompt.create_spinner()
        self.publish_https_spinner = self.prompt.create_spinner()
Example #11
0
def initialize(context):
    structure.ensure_repo_structure(context.cli)
    upload_manager = _upload_manager(context)

    repo_section = structure.repo_section(context.cli)
    repo_section.add_command(repo_create_update.RpmRepoCreateCommand(context))
    repo_section.add_command(repo_create_update.RpmRepoUpdateCommand(context))
    repo_section.add_command(cudl.DeleteRepositoryCommand(context))
    repo_section.add_command(repo_list.RpmRepoListCommand(context))
    repo_section.add_command(
        RepoSearchCommand(context, constants.REPO_NOTE_RPM))

    copy_section = structure.repo_copy_section(context.cli)
    copy_section.add_command(copy_commands.RpmCopyCommand(context))
    copy_section.add_command(copy_commands.ErrataCopyCommand(context))
    copy_section.add_command(copy_commands.DistributionCopyCommand(context))
    copy_section.add_command(copy_commands.PackageGroupCopyCommand(context))
    copy_section.add_command(copy_commands.PackageCategoryCopyCommand(context))
    copy_section.add_command(
        copy_commands.PackageEnvironmentCopyCommand(context))
    copy_section.add_command(copy_commands.AllCopyCommand(context))
    copy_section.add_command(copy_commands.SrpmCopyCommand(context))
    copy_section.add_command(copy_commands.YumRepoMetadataFileCommand(context))
    copy_section.add_command(copy_commands.DrpmCopyCommand(context))

    # Disabled as per 950690. We'll likely be able to add these back once the new
    # yum importer is finished and DRPMs are properly handled.
    # copy_section.add_command(copy_commands.DrpmCopyCommand(context))

    remove_section = structure.repo_remove_section(context.cli)
    remove_section.add_command(remove.RpmRemoveCommand(context))
    remove_section.add_command(remove.SrpmRemoveCommand(context))
    remove_section.add_command(remove.DrpmRemoveCommand(context))
    remove_section.add_command(remove.ErrataRemoveCommand(context))
    remove_section.add_command(remove.PackageGroupRemoveCommand(context))
    remove_section.add_command(remove.PackageCategoryRemoveCommand(context))
    remove_section.add_command(remove.PackageEnvironmentRemoveCommand(context))
    remove_section.add_command(remove.DistributionRemoveCommand(context))
    remove_section.add_command(remove.YumMetadataFileRemoveCommand(context))

    contents_section = structure.repo_contents_section(context.cli)
    contents_section.add_command(contents.SearchRpmsCommand(context))
    contents_section.add_command(contents.SearchDrpmsCommand(context))
    contents_section.add_command(contents.SearchSrpmsCommand(context))
    contents_section.add_command(contents.SearchPackageGroupsCommand(context))
    contents_section.add_command(
        contents.SearchPackageCategoriesCommand(context))
    contents_section.add_command(
        contents.SearchPackageEnvironmentsCommand(context))
    contents_section.add_command(contents.SearchDistributionsCommand(context))
    contents_section.add_command(contents.SearchErrataCommand(context))
    contents_section.add_command(
        contents.SearchYumMetadataFileCommand(context))

    # Add the group section, all its subsections, and commands
    group_export_section = structure.repo_group_export_section(context.cli)
    renderer = PublishStepStatusRenderer(context)
    group_export_section.add_command(
        export.RpmGroupExportCommand(context, renderer))
    group_export_section.add_command(
        export.GroupExportStatusCommand(context, renderer))

    uploads_section = structure.repo_uploads_section(context.cli)
    uploads_section.add_command(
        package.CreateRpmCommand(context, upload_manager))
    uploads_section.add_command(
        package.CreateSrpmCommand(context, upload_manager))
    uploads_section.add_command(
        errata.CreateErratumCommand(context, upload_manager))
    uploads_section.add_command(
        package_group.CreatePackageGroupCommand(context, upload_manager))
    uploads_section.add_command(
        category.CreatePackageCategoryCommand(context, upload_manager))
    uploads_section.add_command(
        comps.CreateCompsCommand(context, upload_manager))
    uploads_section.add_command(
        environment.CreatePackageEnvironmentCommand(context, upload_manager))
    uploads_section.add_command(upload.ResumeCommand(context, upload_manager))
    uploads_section.add_command(upload.CancelCommand(context, upload_manager))
    uploads_section.add_command(upload.ListCommand(context, upload_manager))

    sync_section = structure.repo_sync_section(context.cli)
    renderer = status.RpmStatusRenderer(context)
    sync_section.add_command(
        sync_publish.RunSyncRepositoryCommand(context, renderer))
    sync_section.add_command(sync_publish.SyncStatusCommand(context, renderer))

    publish_section = structure.repo_publish_section(context.cli)
    renderer = PublishStepStatusRenderer(context)
    distributor_id = ids.TYPE_ID_DISTRIBUTOR_YUM
    publish_section.add_command(
        sync_publish.RunPublishRepositoryCommand(context, renderer,
                                                 distributor_id))
    publish_section.add_command(
        sync_publish.PublishStatusCommand(context, renderer))

    repo_export_section = structure.repo_export_section(context.cli)
    renderer = PublishStepStatusRenderer(context)
    repo_export_section.add_command(export.RpmExportCommand(context, renderer))
    repo_export_section.add_command(
        sync_publish.PublishStatusCommand(context,
                                          renderer,
                                          description=DESC_EXPORT_STATUS))

    sync_schedules_section = structure.repo_sync_schedules_section(context.cli)
    sync_schedules_section.add_command(
        sync_schedules.RpmCreateScheduleCommand(context))
    sync_schedules_section.add_command(
        sync_schedules.RpmUpdateScheduleCommand(context))
    sync_schedules_section.add_command(
        sync_schedules.RpmDeleteScheduleCommand(context))
    sync_schedules_section.add_command(
        sync_schedules.RpmListScheduleCommand(context))

    sync_schedules_section.add_command(
        sync_schedules.RpmNextRunCommand(context))
Example #12
0
class RpmStatusRenderer(StatusRenderer):
    def __init__(self, context):
        super(RpmStatusRenderer, self).__init__(context)

        self.publish_steps_renderer = PublishStepStatusRenderer(context)

        # Sync Steps
        self.metadata_last_state = constants.STATE_NOT_STARTED
        self.download_last_state = constants.STATE_NOT_STARTED
        self.distribution_sync_last_state = constants.STATE_NOT_STARTED
        self.errata_last_state = constants.STATE_NOT_STARTED
        self.comps_last_state = constants.STATE_NOT_STARTED
        self.purge_duplicates_last_state = constants.STATE_NOT_STARTED

        # Publish Steps
        self.publish_steps_last_state = dict.fromkeys(constants.PUBLISH_STEPS,
                                                      constants.STATE_NOT_STARTED)

        self.distribution_publish_last_state = constants.STATE_NOT_STARTED
        self.generate_metadata_last_state = constants.STATE_NOT_STARTED
        self.publish_http_last_state = constants.STATE_NOT_STARTED
        self.publish_https_last_state = constants.STATE_NOT_STARTED

        # UI Widgets
        self.metadata_spinner = self.prompt.create_spinner()
        self.download_bar = self.prompt.create_progress_bar()
        self.download_spinner = self.prompt.create_spinner()
        self.distribution_sync_bar = self.prompt.create_progress_bar()
        self.errata_spinner = self.prompt.create_spinner()
        self.comps_spinner = self.prompt.create_spinner()
        self.purge_duplicates_spinner = self.prompt.create_spinner()

        self.packages_bar = self.prompt.create_progress_bar()
        self.distribution_publish_bar = self.prompt.create_progress_bar()
        self.generate_metadata_spinner = self.prompt.create_spinner()
        self.publish_http_spinner = self.prompt.create_spinner()
        self.publish_https_spinner = self.prompt.create_spinner()

    def display_report(self, progress_report):
        """
        Displays the contents of the progress report to the user. This will
        aggregate the calls to render individual sections of the report.
        """

        # There's a small race condition where the task will indicate it's
        # begun running but the importer has yet to submit a progress report
        # (or it has yet to be saved into the task). This should be alleviated
        # by the if statements below.
        try:
            # Sync Steps
            if 'yum_importer' in progress_report:
                self.render_metadata_step(progress_report)
                self.render_download_step(progress_report)
                self.render_distribution_sync_step(progress_report)
                self.render_errata_step(progress_report)
                self.render_comps_step(progress_report)
                self.render_purge_duplicates_step(progress_report)

            # Publish Steps
            if ids.YUM_DISTRIBUTOR_ID in progress_report:
                # Proxy to the standard renderer
                self.publish_steps_renderer.display_report(progress_report)

        except CancelException:
            self.prompt.render_failure_message(_('Operation canceled.'))

    def check_for_cancelled_state(self, state):
        if state == constants.STATE_CANCELLED:
            raise CancelException

    # -- render sync steps -----------------------------------------------------

    def render_metadata_step(self, progress_report):

        # Example Data:
        # "metadata": {
        # "state": "FINISHED"
        # }

        current_state = progress_report['yum_importer']['metadata']['state']
        self.check_for_cancelled_state(current_state)

        def update_func(new_state):
            self.metadata_last_state = new_state

        render_general_spinner_step(self.prompt, self.metadata_spinner, current_state,
                                    self.metadata_last_state, _('Downloading metadata...'),
                                    update_func)

        if self.metadata_last_state == constants.STATE_FAILED:
            self.prompt.render_failure_message(progress_report['yum_importer']['metadata']['error'])

    def render_distribution_sync_step(self, progress_report):
        data = progress_report['yum_importer']['distribution']
        state = data['state']
        self.check_for_cancelled_state(state)
        # Render nothing if we haven't begun yet or if this step is skipped
        if state in (constants.STATE_NOT_STARTED, constants.STATE_SKIPPED):
            return

        # Only render this on the first non-not-started state
        if self.distribution_sync_last_state == constants.STATE_NOT_STARTED:
            self.prompt.write(_('Downloading distribution files...'))

        if (state in (constants.STATE_RUNNING, constants.STATE_COMPLETE) and
                self.distribution_sync_last_state not in constants.COMPLETE_STATES):
            render_itemized_in_progress_state(self.prompt, data, _('distributions'),
                                              self.distribution_sync_bar, state)

        elif state in constants.STATE_FAILED and \
                self.distribution_sync_last_state not in constants.COMPLETE_STATES:

            self.prompt.render_spacer()
            self.prompt.render_failure_message(_('Errors encountered during distribution sync:'))

            # TODO: read this from config
            # display_error_count = self.context.extension_config.getint('main',
            # 'num_display_errors')
            display_error_count = 5

            num_errors = min(len(data['error_details']), display_error_count)

            if num_errors > 0:

                # Each error is a list of filename and dict of details
                # Example:
                # "error_details": [
                #      [
                #        "file:///mnt/iso/f18/images/boot.iso",
                #        {
                #          "response_code": 0,
                #          "error_message": "Couldn't open file /mnt/iso/f18/images/boot.iso",
                #          "error_code": 37
                #        }
                #      ]
                #    ],

                for i in range(0, num_errors):
                    error = data['error_details'][i]

                    message_data = {
                        'filename': error[0],
                        'message': error[1].get('error_message'),
                        'code': error[1].get('error_code'),
                    }

                    template = 'File: %(filename)s\n'
                    template += 'Error Code:   %(code)s\n'
                    template += 'Error Message: %(message)s'
                    message = template % message_data

                    self.prompt.render_failure_message(message)
                self.prompt.render_spacer()

        self.distribution_sync_last_state = state

    def render_download_step(self, progress_report):
        """
        :param progress_report: A dictionary containing a key called 'yum_importer' that is a
                                dictionary that has a key that is 'content' that indexes a
                                pulp_rpm.plugins.importers.yum.report.ContentReport.
        :type  progress_report: dict
        """
        data = progress_report['yum_importer']['content']
        state = data['state']
        self.check_for_cancelled_state(state)

        # Render nothing if we haven't begun yet or if this step is skipped
        if state in (constants.STATE_NOT_STARTED, constants.STATE_SKIPPED):
            return

        details = data['details']

        # Only render this on the first non-not-started state
        if self.download_last_state == constants.STATE_NOT_STARTED:
            self.prompt.write(_('Downloading repository content...'))

        # If it's running or finished, the output is still the same. This way,
        # if the status is viewed after this step, the content download
        # summary is still available.

        if state in (constants.STATE_RUNNING, constants.STATE_COMPLETE) and \
           self.download_last_state not in constants.COMPLETE_STATES:

            self.download_last_state = state

            template = _('RPMs:       %(rpm_done)s/%(rpm_total)s items\n'
                         'Delta RPMs: %(drpm_done)s/%(drpm_total)s items\n')

            bar_message = template % details

            overall_done = data['size_total'] - data['size_left']
            overall_total = data['size_total']

            try:
                self.download_bar.render(overall_done, overall_total, message=bar_message)
            except ZeroDivisionError:
                # overall_total is 0 -- render a spinner until we know enough to make a bar
                self.download_spinner.next()

            if state == constants.STATE_COMPLETE:
                # If all of the packages are already downloaded and up to date, the overall total
                # will be 0. In that event, fill the download bar since the state is complete.
                if overall_total == 0:
                    overall_total = overall_done = 1
                    self.download_bar.render(overall_done, overall_total, message=bar_message)
                self.prompt.write(_('... completed'))
                self.prompt.render_spacer()

                # If there are any errors, write them out here
                # TODO: read this from config
                # display_error_count = self.context.extension_config.getint('main',
                # 'num_display_errors')
                display_error_count = 5

                num_errors = min(len(data['error_details']), display_error_count)

                if num_errors > 0:
                    self.prompt.render_failure_message(
                        _('Individual package errors encountered during sync:'))

                    for i in range(0, num_errors):
                        error = data['error_details'][i]
                        if error.get(constants.ERROR_CODE) == constants.ERROR_CHECKSUM_TYPE_UNKNOWN:
                            message_data = {
                                'name': error[constants.NAME],
                                'checksum_type': error[constants.CHECKSUM_TYPE],
                                'accepted': ','.join(
                                    error.get(constants.ACCEPTED_CHECKSUM_TYPES, []))
                            }
                            template = _('Package: %(name)s\nError: An invalid checksum type '
                                         '(%(checksum_type)s) was detected.\n'
                                         'Accepted checksum types: %(accepted)s')
                        elif error.get(constants.ERROR_CODE) == constants.ERROR_INVALID_PACKAGE_SIG:
                            message_data = {
                                'count': error['count'],
                            }
                            template = _('%(count)s packages failed signature filter and were not '
                                         'imported.')

                        elif error.get(
                                constants.ERROR_CODE) == constants.ERROR_CHECKSUM_VERIFICATION:
                            message_data = {
                                'name': error[constants.NAME],
                            }
                            template = _('Package: %(name)s\nError: An invalid checksum was '
                                         'detected.')

                        elif error.get(constants.ERROR_CODE) == constants.ERROR_SIZE_VERIFICATION:
                            message_data = {
                                'name': error[constants.NAME],
                            }
                            template = _('Package: %(name)s\nError: The size did not match the '
                                         'value specified in the repository metadata.')
                        else:
                            error_msg = error.get('error', '')
                            traceback = '\n'.join(error.get('traceback', []))

                            message_data = {
                                'name': error['url'],
                                'error': error_msg,
                                'traceback': traceback
                            }

                            template = 'Package: %(name)s\n'
                            template += 'Error:   %(error)s\n'
                            if message_data["traceback"]:
                                template += 'Traceback:\n'
                                template += '%(traceback)s'

                        message = template % message_data

                        self.prompt.render_failure_message(message)
                    self.prompt.render_spacer()

        elif state == constants.STATE_FAILED and self.download_last_state not in \
                constants.COMPLETE_STATES:

            # This state means something went horribly wrong. There won't be
            # individual package error details which is why they are only
            # displayed above and not in this case.

            self.prompt.write(_('... failed'))
            self.download_last_state = constants.STATE_FAILED

    def render_errata_step(self, progress_report):

        # Example Data:
        # "errata": {
        # "state": "FINISHED",
        #    "num_errata": 0
        # }
        current_state = progress_report['yum_importer']['errata']['state']
        self.check_for_cancelled_state(current_state)
        if current_state in (constants.STATE_NOT_STARTED, constants.STATE_SKIPPED):
            return

        def update_func(new_state):
            self.errata_last_state = new_state

        render_general_spinner_step(self.prompt, self.errata_spinner, current_state,
                                    self.errata_last_state, _('Importing errata...'), update_func)

    def render_comps_step(self, progress_report):
        # Example Data:
        # "comps": {
        # "state": "FINISHED",
        #    "num_available_groups": 0,
        #    "num_available_categories": 0,
        #    "num_orphaned_groups": 0,
        #    "num_orphaned_categories": 0,
        #    "num_new_groups": 0,
        #    "num_new_categories": 0,
        # }

        current_state = progress_report['yum_importer']['comps']['state']

        def update_func(new_state):
            self.comps_last_state = new_state

        render_general_spinner_step(self.prompt, self.comps_spinner, current_state,
                                    self.comps_last_state,
                                    _('Importing package groups/categories...'), update_func)

    def render_purge_duplicates_step(self, progress_report):
        # Example Data:
        # "purge_duplicates": {
        #   "state": "FINISHED"
        # }

        current_state = progress_report['yum_importer']['purge_duplicates']['state']

        def update_func(new_state):
            self.purge_duplicates_last_state = new_state

        render_general_spinner_step(self.prompt, self.purge_duplicates_spinner, current_state,
                                    self.purge_duplicates_last_state,
                                    _('Cleaning duplicate packages...'), update_func)
Example #13
0
class RpmStatusRenderer(StatusRenderer):
    def __init__(self, context):
        super(RpmStatusRenderer, self).__init__(context)

        self.publish_steps_renderer = PublishStepStatusRenderer(context)

        # Sync Steps
        self.metadata_last_state = constants.STATE_NOT_STARTED
        self.download_last_state = constants.STATE_NOT_STARTED
        self.distribution_sync_last_state = constants.STATE_NOT_STARTED
        self.errata_last_state = constants.STATE_NOT_STARTED
        self.comps_last_state = constants.STATE_NOT_STARTED

        # Publish Steps
        self.publish_steps_last_state = dict.fromkeys(
            constants.PUBLISH_STEPS, constants.STATE_NOT_STARTED)

        self.distribution_publish_last_state = constants.STATE_NOT_STARTED
        self.generate_metadata_last_state = constants.STATE_NOT_STARTED
        self.publish_http_last_state = constants.STATE_NOT_STARTED
        self.publish_https_last_state = constants.STATE_NOT_STARTED

        # UI Widgets
        self.metadata_spinner = self.prompt.create_spinner()
        self.download_bar = self.prompt.create_progress_bar()
        self.distribution_sync_bar = self.prompt.create_progress_bar()
        self.errata_spinner = self.prompt.create_spinner()
        self.comps_spinner = self.prompt.create_spinner()

        self.packages_bar = self.prompt.create_progress_bar()
        self.distribution_publish_bar = self.prompt.create_progress_bar()
        self.generate_metadata_spinner = self.prompt.create_spinner()
        self.publish_http_spinner = self.prompt.create_spinner()
        self.publish_https_spinner = self.prompt.create_spinner()

    def display_report(self, progress_report):
        """
        Displays the contents of the progress report to the user. This will
        aggregate the calls to render individual sections of the report.
        """

        # There's a small race condition where the task will indicate it's
        # begun running but the importer has yet to submit a progress report
        # (or it has yet to be saved into the task). This should be alleviated
        # by the if statements below.
        try:
            # Sync Steps
            if 'yum_importer' in progress_report:
                self.render_metadata_step(progress_report)
                self.render_download_step(progress_report)
                self.render_distribution_sync_step(progress_report)
                self.render_errata_step(progress_report)
                self.render_comps_step(progress_report)

            # Publish Steps
            if ids.YUM_DISTRIBUTOR_ID in progress_report:
                # Proxy to the standard renderer
                self.publish_steps_renderer.display_report(progress_report)

        except CancelException:
            self.prompt.render_failure_message(_('Operation canceled.'))

    def check_for_cancelled_state(self, state):
        if state == constants.STATE_CANCELLED:
            raise CancelException

    # -- render sync steps -----------------------------------------------------

    def render_metadata_step(self, progress_report):

        # Example Data:
        # "metadata": {
        # "state": "FINISHED"
        # }

        current_state = progress_report['yum_importer']['metadata']['state']
        self.check_for_cancelled_state(current_state)

        def update_func(new_state):
            self.metadata_last_state = new_state

        render_general_spinner_step(self.prompt, self.metadata_spinner,
                                    current_state, self.metadata_last_state,
                                    _('Downloading metadata...'), update_func)

        if self.metadata_last_state == constants.STATE_FAILED:
            self.prompt.render_failure_message(
                progress_report['yum_importer']['metadata']['error'])

    def render_distribution_sync_step(self, progress_report):
        data = progress_report['yum_importer']['distribution']
        state = data['state']
        self.check_for_cancelled_state(state)
        # Render nothing if we haven't begun yet or if this step is skipped
        if state in (constants.STATE_NOT_STARTED, constants.STATE_SKIPPED):
            return

        # Only render this on the first non-not-started state
        if self.distribution_sync_last_state == constants.STATE_NOT_STARTED:
            self.prompt.write(_('Downloading distribution files...'))

        if (state in (constants.STATE_RUNNING, constants.STATE_COMPLETE)
                and self.distribution_sync_last_state
                not in constants.COMPLETE_STATES):
            render_itemized_in_progress_state(self.prompt, data,
                                              _('distributions'),
                                              self.distribution_sync_bar,
                                              state)

        elif state in constants.STATE_FAILED and \
                self.distribution_sync_last_state not in constants.COMPLETE_STATES:

            self.prompt.render_spacer()
            self.prompt.render_failure_message(
                _('Errors encountered during distribution sync:'))

            # TODO: read this from config
            # display_error_count = self.context.extension_config.getint('main',
            # 'num_display_errors')
            display_error_count = 5

            num_errors = min(len(data['error_details']), display_error_count)

            if num_errors > 0:

                # Each error is a list of filename and dict of details
                # Example:
                # "error_details": [
                #      [
                #        "file:///mnt/iso/f18/images/boot.iso",
                #        {
                #          "response_code": 0,
                #          "error_message": "Couldn't open file /mnt/iso/f18/images/boot.iso",
                #          "error_code": 37
                #        }
                #      ]
                #    ],

                for i in range(0, num_errors):
                    error = data['error_details'][i]

                    message_data = {
                        'filename': error[0],
                        'message': error[1].get('error_message'),
                        'code': error[1].get('error_code'),
                    }

                    template = 'File: %(filename)s\n'
                    template += 'Error Code:   %(code)s\n'
                    template += 'Error Message: %(message)s'
                    message = template % message_data

                    self.prompt.render_failure_message(message)
                self.prompt.render_spacer()

        self.distribution_sync_last_state = state

    def render_download_step(self, progress_report):
        """
        :param progress_report: A dictionary containing a key called 'yum_importer' that is a
                                dictionary that has a key that is 'content' that indexes a
                                pulp_rpm.plugins.importers.yum.report.ContentReport.
        :type  progress_report: dict
        """
        data = progress_report['yum_importer']['content']
        state = data['state']
        self.check_for_cancelled_state(state)

        # Render nothing if we haven't begun yet or if this step is skipped
        if state in (constants.STATE_NOT_STARTED, constants.STATE_SKIPPED):
            return

        details = data['details']

        # Only render this on the first non-not-started state
        if self.download_last_state == constants.STATE_NOT_STARTED:
            self.prompt.write(_('Downloading repository content...'))

        # If it's running or finished, the output is still the same. This way,
        # if the status is viewed after this step, the content download
        # summary is still available.

        if state in (constants.STATE_RUNNING, constants.STATE_COMPLETE) and \
           self.download_last_state not in constants.COMPLETE_STATES:

            self.download_last_state = state

            template = _('RPMs:       %(rpm_done)s/%(rpm_total)s items\n'
                         'Delta RPMs: %(drpm_done)s/%(drpm_total)s items\n')

            bar_message = template % details

            overall_done = data['size_total'] - data['size_left']
            overall_total = data['size_total']

            # If all of the packages are already downloaded and up to date,
            # the total bytes to process will be 0. This means the download
            # step is basically finished, so fill the progress bar.
            if overall_total == 0:
                overall_total = overall_done = 1

            self.download_bar.render(overall_done,
                                     overall_total,
                                     message=bar_message)

            if state == constants.STATE_COMPLETE:
                self.prompt.write(_('... completed'))
                self.prompt.render_spacer()

                # If there are any errors, write them out here
                # TODO: read this from config
                # display_error_count = self.context.extension_config.getint('main',
                # 'num_display_errors')
                display_error_count = 5

                num_errors = min(len(data['error_details']),
                                 display_error_count)

                if num_errors > 0:
                    self.prompt.render_failure_message(
                        _('Individual package errors encountered during sync:')
                    )

                    for i in range(0, num_errors):
                        error = data['error_details'][i]
                        if error.get(
                                constants.ERROR_CODE
                        ) == constants.ERROR_CHECKSUM_TYPE_UNKNOWN:
                            message_data = {
                                'name':
                                error[constants.NAME],
                                'checksum_type':
                                error[constants.CHECKSUM_TYPE],
                                'accepted':
                                ','.join(
                                    error.get(
                                        constants.ACCEPTED_CHECKSUM_TYPES, []))
                            }
                            template = _(
                                'Package: %(name)s\nError: An invalid checksum type '
                                '(%(checksum_type)s) was detected.\n'
                                'Accepted checksum types: %(accepted)s')
                        elif error.get(
                                constants.ERROR_CODE
                        ) == constants.ERROR_CHECKSUM_VERIFICATION:
                            message_data = {
                                'name': error[constants.NAME],
                            }
                            template = _(
                                'Package: %(name)s\nError: An invalid checksum was '
                                'detected.')

                        elif error.get(constants.ERROR_CODE
                                       ) == constants.ERROR_SIZE_VERIFICATION:
                            message_data = {
                                'name': error[constants.NAME],
                            }
                            template = _(
                                'Package: %(name)s\nError: The size did not match the '
                                'value specified in the repository metadata.')
                        else:
                            error_msg = error.get('error', '')
                            traceback = '\n'.join(error.get('traceback', []))

                            message_data = {
                                'name': error['url'],
                                'error': error_msg,
                                'traceback': traceback
                            }

                            template = 'Package: %(name)s\n'
                            template += 'Error:   %(error)s\n'
                            if message_data["traceback"]:
                                template += 'Traceback:\n'
                                template += '%(traceback)s'

                        message = template % message_data

                        self.prompt.render_failure_message(message)
                    self.prompt.render_spacer()

        elif state == constants.STATE_FAILED and self.download_last_state not in \
                constants.COMPLETE_STATES:

            # This state means something went horribly wrong. There won't be
            # individual package error details which is why they are only
            # displayed above and not in this case.

            self.prompt.write(_('... failed'))
            self.download_last_state = constants.STATE_FAILED

    def render_errata_step(self, progress_report):

        # Example Data:
        # "errata": {
        # "state": "FINISHED",
        #    "num_errata": 0
        # }
        current_state = progress_report['yum_importer']['errata']['state']
        self.check_for_cancelled_state(current_state)
        if current_state in (constants.STATE_NOT_STARTED,
                             constants.STATE_SKIPPED):
            return

        def update_func(new_state):
            self.errata_last_state = new_state

        render_general_spinner_step(self.prompt, self.errata_spinner,
                                    current_state, self.errata_last_state,
                                    _('Importing errata...'), update_func)

    def render_comps_step(self, progress_report):
        # Example Data:
        # "comps": {
        # "state": "FINISHED",
        #    "num_available_groups": 0,
        #    "num_available_categories": 0,
        #    "num_orphaned_groups": 0,
        #    "num_orphaned_categories": 0,
        #    "num_new_groups": 0,
        #    "num_new_categories": 0,
        # }

        current_state = progress_report['yum_importer']['comps']['state']

        def update_func(new_state):
            self.comps_last_state = new_state

        render_general_spinner_step(
            self.prompt, self.comps_spinner,
            current_state, self.comps_last_state,
            _('Importing package groups/categories...'), update_func)