forked from pulp/pulp
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request pulp#25 from pulp/jdob-puppet
CLI refactoring of sync related commands and Puppet implementation of the progress reporting
- Loading branch information
Showing
32 changed files
with
2,109 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright © 2012 Red Hat, Inc. | ||
# | ||
# This software is licensed to you under the GNU General Public | ||
# License as published by the Free Software Foundation; either version | ||
# 2 of the License (GPLv2) or (at your option) any later version. | ||
# There is NO WARRANTY for this software, express or implied, | ||
# including the implied warranties of MERCHANTABILITY, | ||
# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should | ||
# have received a copy of GPLv2 along with this software; if not, see | ||
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. |
131 changes: 131 additions & 0 deletions
131
platform/src/pulp/client/commands/repo/status/status.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright © 2012 Red Hat, Inc. | ||
# | ||
# This software is licensed to you under the GNU General Public | ||
# License as published by the Free Software Foundation; either version | ||
# 2 of the License (GPLv2) or (at your option) any later version. | ||
# There is NO WARRANTY for this software, express or implied, | ||
# including the implied warranties of MERCHANTABILITY, | ||
# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should | ||
# have received a copy of GPLv2 along with this software; if not, see | ||
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
|
||
""" | ||
Contains functions for rendering the sync/publish progress reports. | ||
""" | ||
|
||
from gettext import gettext as _ | ||
import time | ||
|
||
# -- public ------------------------------------------------------------------- | ||
|
||
def display_task_status(context, renderer, task_id): | ||
""" | ||
Displays and continues to poll and update the sync or publish operation | ||
taking place in the given task. | ||
:param context: CLI context | ||
:type context: pulp.client.extensions.core.ClientContext | ||
:param renderer: StatusRenderer subclass that will interpret the sync or | ||
publish progress report | ||
:type renderer: StatusRenderer | ||
:param task_id: task to display | ||
:type task_id: str | ||
""" | ||
|
||
# Retrieve the task and wrap into a list for consistent rendering | ||
response = context.server.tasks.get_task(task_id) | ||
task_list = [response.response_body] | ||
|
||
_display_status(context, renderer, task_list) | ||
|
||
def display_group_status(context, renderer, task_group_id): | ||
""" | ||
Displays and continues to poll and update the sync or publish operation | ||
taking place in the given task group. This call is used for tracking | ||
sync operations with one or more distributors configured for auto | ||
publish. | ||
:param context: CLI context | ||
:type context: pulp.client.extensions.core.ClientContext | ||
:param renderer: StatusRenderer subclass that will interpret the sync or | ||
publish progress report | ||
:type renderer: StatusRenderer | ||
:param task_group_id: task group to display | ||
:type task_group_id: str | ||
""" | ||
|
||
# Get the list of tasks relevant to the group | ||
response = context.server.task_groups.get_task_group(task_group_id) | ||
task_list = response.response_body | ||
|
||
_display_status(context, renderer, task_list) | ||
|
||
# -- private ------------------------------------------------------------------ | ||
|
||
def _display_status(context, renderer, task_list): | ||
|
||
m = _('This command may be exited by pressing ctrl+c without affecting the actual operation on the server.') | ||
context.prompt.render_paragraph(m, tag='ctrl-c') | ||
|
||
# Handle the cases where we don't want to honor the foreground request | ||
if task_list[0].is_rejected(): | ||
announce = _('The request to synchronize repository was rejected') | ||
description = _('This is likely due to an impending delete request for the repository.') | ||
|
||
context.prompt.render_failure_message(announce, tag='rejected-msg') | ||
context.prompt.render_paragraph(description, tag='rejected-desc') | ||
return | ||
|
||
if task_list[0].is_postponed(): | ||
a = _('The request to synchronize the repository was accepted but postponed ' | ||
'due to one or more previous requests against the repository. The sync will ' | ||
'take place at the earliest possible time.') | ||
context.prompt.render_paragraph(a, tag='postponed') | ||
return | ||
|
||
try: | ||
for task_num, task in enumerate(task_list): | ||
quiet_waiting = task_num > 0 | ||
|
||
_display_task_status(context, renderer, task.task_id, quiet_waiting=quiet_waiting) | ||
|
||
except KeyboardInterrupt: | ||
# If the user presses ctrl+c, don't let the error bubble up, just | ||
# exit gracefully | ||
return | ||
|
||
def _display_task_status(context, renderer, task_id, quiet_waiting=False): | ||
""" | ||
Poll an individual task and display the progress for it. | ||
:return: the completed task | ||
:rtype: Task | ||
""" | ||
|
||
begin_spinner = context.prompt.create_spinner() | ||
poll_frequency_in_seconds = float(context.config['output']['poll_frequency_in_seconds']) | ||
|
||
response = context.server.tasks.get_task(task_id) | ||
|
||
while not response.response_body.is_completed(): | ||
|
||
if response.response_body.is_waiting() and not quiet_waiting: | ||
begin_spinner.next(_('Waiting to begin')) | ||
else: | ||
renderer.display_report(response.response_body.progress) | ||
|
||
time.sleep(poll_frequency_in_seconds) | ||
|
||
response = context.server.tasks.get_task(response.response_body.task_id) | ||
|
||
# Even after completion, we still want to display the report one last | ||
# time in case there was no poll between, say, the middle of the | ||
# package download and when the task itself reports as finished. We | ||
# don't want to leave the UI in that half-finished state so this final | ||
# call is to clean up and render the completed report. | ||
renderer.display_report(response.response_body.progress) | ||
|
||
return response.response_body | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright © 2012 Red Hat, Inc. | ||
# | ||
# This software is licensed to you under the GNU General Public | ||
# License as published by the Free Software Foundation; either version | ||
# 2 of the License (GPLv2) or (at your option) any later version. | ||
# There is NO WARRANTY for this software, express or implied, | ||
# including the implied warranties of MERCHANTABILITY, | ||
# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should | ||
# have received a copy of GPLv2 along with this software; if not, see | ||
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
|
||
""" | ||
Functions for working with sync/publish tasks in the server. | ||
""" | ||
|
||
from pulp.common import tags | ||
|
||
|
||
def relevant_existing_task_id(existing_sync_tasks): | ||
""" | ||
Analyzes the list of existing sync tasks to determine which should be | ||
tracked by the CLI. | ||
:param existing_sync_tasks: list of task instances retrieved from the server | ||
:type existing_sync_tasks: list | ||
:return: ID of the task that should be displayed | ||
:rtype: str | ||
""" | ||
|
||
# At this point, we have at least one sync task but that doesn't | ||
# mean it's running yet. It shouldn't, however, be completed as | ||
# it wouldn't come back in the lookup. That should leave two | ||
# possibilities: waiting or running. | ||
# | ||
# There will only be one running, so that case is easy: if we find | ||
# a running task start displaying it. | ||
# | ||
# If there are no running tasks, the waiting ones are ordered such | ||
# that the first one will execute next, so use that task ID and | ||
# start the display process (it will handle waiting accordingly. | ||
|
||
running_tasks = [t for t in existing_sync_tasks if t.is_running()] | ||
waiting_tasks = [t for t in existing_sync_tasks if t.is_waiting()] | ||
|
||
if running_tasks: | ||
return running_tasks[0].task_id | ||
elif waiting_tasks: | ||
return waiting_tasks[0].task_id | ||
|
||
return None | ||
|
||
|
||
def relevant_existing_task_group_id(existing_sync_tasks): | ||
""" | ||
Grok through a list of existing sync tasks and look for the task_group_id | ||
for the highest priority sync. | ||
""" | ||
running_tasks = [t for t in existing_sync_tasks if t.is_running()] | ||
waiting_tasks = [t for t in existing_sync_tasks if t.is_waiting()] | ||
|
||
if running_tasks: | ||
return running_tasks[0].task_group_id | ||
elif waiting_tasks: | ||
return waiting_tasks[0].task_group_id | ||
|
||
return None | ||
|
||
|
||
def sync_task_in_sync_task_group(task_list): | ||
""" | ||
Grok through the tasks returned from the server's repo sync call and find | ||
the task that pertains to the sync itself. | ||
:param task_list: list of tasks | ||
:type task_list: list | ||
:return: task for the sync | ||
:rtype: Task | ||
""" | ||
sync_tag = tags.action_tag(tags.ACTION_SYNC_TYPE) | ||
for t in task_list: | ||
if sync_tag in t.tags: | ||
return t | ||
return None | ||
|
||
|
||
def publish_task_in_sync_task_group(task_list): | ||
""" | ||
Grok through the tasks returned from the server's repo sync call and find | ||
the task that pertains to the auto publish. | ||
:param task_list: list of tasks | ||
:type task_list: list | ||
:return: task for the publish | ||
:rtype: Task | ||
""" | ||
publish_tag = tags.action_tag(tags.ACTION_AUTO_PUBLISH_TYPE) | ||
for t in task_list: | ||
if publish_tag in t.tags: | ||
return t | ||
return None | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright © 2012 Red Hat, Inc. | ||
# | ||
# This software is licensed to you under the GNU General Public | ||
# License as published by the Free Software Foundation; either version | ||
# 2 of the License (GPLv2) or (at your option) any later version. | ||
# There is NO WARRANTY for this software, express or implied, | ||
# including the implied warranties of MERCHANTABILITY, | ||
# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should | ||
# have received a copy of GPLv2 along with this software; if not, see | ||
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
|
||
""" | ||
Commands and hooks for creating and using sync, publish, and progress status | ||
commands. | ||
""" | ||
|
||
from gettext import gettext as _ | ||
|
||
from pulp.client.commands import options | ||
from pulp.client.commands.repo.status import status, tasks | ||
from pulp.client.extensions.extensions import PulpCliCommand | ||
|
||
# -- constants ---------------------------------------------------------------- | ||
|
||
# Command Descriptions | ||
|
||
DESC_SYNC_RUN = _('triggers an immediate sync of a repository') | ||
DESC_STATUS = _('displays the status of a repository\'s sync tasks') | ||
|
||
NAME_BACKGROUND = 'bg' | ||
DESC_BACKGROUND = _('if specified, the CLI process will end but the sync will continue on ' | ||
'the server; the progress can be later displayed using the status command') | ||
|
||
# -- hooks -------------------------------------------------------------------- | ||
|
||
class StatusRenderer(object): | ||
|
||
def __init__(self, context): | ||
self.context = context | ||
self.prompt = context.prompt | ||
|
||
def display_report(self, progress_report): | ||
raise NotImplementedError() | ||
|
||
# -- commands ----------------------------------------------------------------- | ||
|
||
class RunSyncRepositoryCommand(PulpCliCommand): | ||
""" | ||
Requests an immediate sync for a repository. If the sync begins (it is not | ||
postponed or rejected), the provided renderer will be used to track its | ||
progress. The user has the option to exit the progress polling or skip it | ||
entirely through a flag on the run command. | ||
""" | ||
|
||
def __init__(self, context, renderer): | ||
super(RunSyncRepositoryCommand, self).__init__('run', DESC_SYNC_RUN, self.run) | ||
|
||
self.context = context | ||
self.prompt = context.prompt | ||
self.renderer = renderer | ||
|
||
self.add_option(options.OPTION_REPO_ID) | ||
self.create_flag('--' + NAME_BACKGROUND, DESC_BACKGROUND) | ||
|
||
def run(self, **kwargs): | ||
repo_id = kwargs[options.OPTION_REPO_ID.keyword] | ||
background = kwargs[NAME_BACKGROUND] | ||
|
||
self.prompt.render_title(_('Synchronizing Repository [%(r)s]') % {'r' : repo_id}) | ||
|
||
# See if an existing sync is running for the repo. If it is, resume | ||
# progress tracking. | ||
existing_sync_tasks = self.context.server.tasks.get_repo_sync_tasks(repo_id).response_body | ||
task_group_id = tasks.relevant_existing_task_group_id(existing_sync_tasks) | ||
|
||
if task_group_id is not None: | ||
msg = _('A sync task is already in progress for this repository. ') | ||
if not background: | ||
msg += _('Its progress will be tracked below.') | ||
self.context.prompt.render_paragraph(msg, tag='in-progress') | ||
|
||
else: | ||
# Trigger the actual sync | ||
response = self.context.server.repo_actions.sync(repo_id, None) | ||
sync_task = tasks.sync_task_in_sync_task_group(response.response_body) | ||
task_group_id = sync_task.task_group_id | ||
|
||
if not background: | ||
status.display_group_status(self.context, self.renderer, task_group_id) | ||
else: | ||
msg = _('The status of this sync can be displayed using the status command.') | ||
self.context.prompt.render_paragraph(msg, 'background') | ||
|
||
|
||
class SyncStatusCommand(PulpCliCommand): | ||
def __init__(self, context, renderer): | ||
super(SyncStatusCommand, self).__init__('status', DESC_STATUS, self.run) | ||
|
||
self.context = context | ||
self.prompt = context.prompt | ||
self.renderer = renderer | ||
|
||
self.add_option(options.OPTION_REPO_ID) | ||
|
||
def run(self, **kwargs): | ||
pass |
Oops, something went wrong.