aurora-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject incubator-aurora git commit: Suppressing duplicate error messages.
Date Thu, 08 Jan 2015 00:28:11 GMT
Repository: incubator-aurora
Updated Branches:
  refs/heads/master eab94dc10 -> 7449e34d8


Suppressing duplicate error messages.

Bugs closed: AURORA-968

Reviewed at https://reviews.apache.org/r/29015/


Project: http://git-wip-us.apache.org/repos/asf/incubator-aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-aurora/commit/7449e34d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-aurora/tree/7449e34d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-aurora/diff/7449e34d

Branch: refs/heads/master
Commit: 7449e34d8ebd2603bd92d1266f2f031622c61fe7
Parents: eab94dc
Author: Maxim Khutornenko <maxim@apache.org>
Authored: Wed Jan 7 16:27:46 2015 -0800
Committer: -l <maxim@apache.org>
Committed: Wed Jan 7 16:27:46 2015 -0800

----------------------------------------------------------------------
 .../python/apache/aurora/client/cli/context.py  | 51 +++++++-------------
 .../python/apache/aurora/client/cli/cron.py     |  8 +--
 .../python/apache/aurora/client/cli/jobs.py     | 43 ++++++++---------
 .../python/apache/aurora/client/cli/quota.py    | 22 ++-------
 .../python/apache/aurora/client/cli/task.py     |  2 +-
 .../python/apache/aurora/client/cli/update.py   | 17 ++++---
 .../apache/aurora/client/cli/test_create.py     | 27 ++++++-----
 .../apache/aurora/client/cli/test_kill.py       | 42 ++++++++++------
 .../apache/aurora/client/cli/test_quota.py      | 12 +++++
 .../apache/aurora/client/cli/test_restart.py    |  5 +-
 .../apache/aurora/client/cli/test_supdate.py    |  5 +-
 .../apache/aurora/client/cli/test_update.py     |  2 +-
 .../python/apache/aurora/client/cli/util.py     | 18 +++++++
 13 files changed, 133 insertions(+), 121 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/main/python/apache/aurora/client/cli/context.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/context.py b/src/main/python/apache/aurora/client/cli/context.py
index f062afc..5edaf08 100644
--- a/src/main/python/apache/aurora/client/cli/context.py
+++ b/src/main/python/apache/aurora/client/cli/context.py
@@ -62,8 +62,8 @@ def bindings_to_list(bindings):
 class AuroraCommandContext(Context):
 
   LOCK_ERROR_MSG = """Error: job is locked by an incomplete update.
-                      run 'aurora job cancel-update' to release the lock if no update is
in progress
-                   """
+                      run 'aurora job cancel-update' to release the lock if no update
+                      is in progress"""
 
   """A context object used by Aurora commands to manage command processing state
   and common operations.
@@ -93,18 +93,16 @@ class AuroraCommandContext(Context):
         logging.debug("Config: %s" % fp.readlines())
       bindings = bindings_to_list(self.options.bindings) if self.options.bindings else None
       result = get_config(
-        jobname,
-        config_file,
-        self.options.read_json,
-        bindings,
-        select_cluster=jobkey.cluster,
-        select_role=jobkey.role,
-        select_env=jobkey.env)
+          jobname,
+          config_file,
+          self.options.read_json,
+          bindings,
+          select_cluster=jobkey.cluster,
+          select_role=jobkey.role,
+          select_env=jobkey.env)
       check_result = result.raw().check()
       if not check_result.ok():
-        self.print_err(str(check_result))
-        raise self.CommandError(EXIT_INVALID_CONFIGURATION,
-            "Error in configuration")
+        raise self.CommandError(EXIT_INVALID_CONFIGURATION, check_result)
       return result
     except Exception as e:
       raise self.CommandError(EXIT_INVALID_CONFIGURATION, 'Error loading configuration: %s'
% e)
@@ -131,27 +129,14 @@ class AuroraCommandContext(Context):
     self.open_page(synthesize_url(api.scheduler_proxy.scheduler_client().url,
         role, env, name))
 
-  def print_out_response_details(self, resp):
-    if resp.details is not None:
-      for m in resp.details:
-        self.print_out(m.message)
-
-  def log_response(self, resp):
-    if resp.responseCode != ResponseCode.OK:
-      for m in resp.details:
-        self.print_err("\t%s" % m.message)
-    else:
+  def log_response_and_raise(self, resp, err_code=EXIT_API_ERROR, err_msg="Command failure:"):
+    if resp.responseCode == ResponseCode.OK:
       logging.info(combine_messages(resp))
-
-  def check_and_log_response(self, resp, err_code=EXIT_API_ERROR, err_msg=None):
-    if resp.responseCode != ResponseCode.OK:
-      if err_msg is None:
-        err_msg = combine_messages(resp)
-      if resp.responseCode == ResponseCode.LOCK_ERROR:
-        self.print_err(self.LOCK_ERROR_MSG)
+    else:
       self.print_err(err_msg)
-    self.log_response(resp)
-    if resp.responseCode != ResponseCode.OK:
+      self.print_err("\t%s" % combine_messages(resp))
+      if resp.responseCode == ResponseCode.LOCK_ERROR:
+        self.print_err("\t%s" % self.LOCK_ERROR_MSG)
       raise self.CommandErrorLogged(err_code, err_msg)
 
   @classmethod
@@ -183,7 +168,7 @@ class AuroraCommandContext(Context):
     for cluster in clusters:
       api = self.get_api(cluster)
       resp = api.get_jobs(role)
-      self.check_and_log_response(resp, err_code=EXIT_COMMAND_FAILURE)
+      self.log_response_and_raise(resp, err_code=EXIT_COMMAND_FAILURE)
       result.extend([AuroraJobKey(cluster, job.key.role, job.key.environment, job.key.name)
           for job in resp.result.getJobsResult.configs])
     return result
@@ -220,7 +205,7 @@ class AuroraCommandContext(Context):
     """Returns a list of task instances running under the job."""
     api = self.get_api(key.cluster)
     resp = api.check_status(key)
-    self.check_and_log_response(resp, err_code=EXIT_INVALID_PARAMETER)
+    self.log_response_and_raise(resp, err_code=EXIT_INVALID_PARAMETER)
     return resp.result.scheduleStatusResult.tasks or None
 
   def get_active_instances(self, key):

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/main/python/apache/aurora/client/cli/cron.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/cron.py b/src/main/python/apache/aurora/client/cli/cron.py
index 1f1efdb..d7016b1 100644
--- a/src/main/python/apache/aurora/client/cli/cron.py
+++ b/src/main/python/apache/aurora/client/cli/cron.py
@@ -59,7 +59,7 @@ class Schedule(Verb):
           "Non-cron jobs may only be created with \"aurora job create\" command")
 
     resp = api.schedule_cron(config)
-    context.check_and_log_response(resp,
+    context.log_response_and_raise(resp,
         err_msg=("Error scheduling cron job %s:" % context.options.jobspec))
 
     context.print_out("Cron job scheduled, status can be viewed at %s"
@@ -85,7 +85,7 @@ class Deschedule(Verb):
   def execute(self, context):
     api = context.get_api(context.options.jobspec.cluster)
     resp = api.deschedule_cron(context.options.jobspec)
-    context.check_and_log_response(resp,
+    context.log_response_and_raise(resp,
         err_msg=("Error descheduling cron job %s:" % context.options.jobspec))
     context.print_out("Cron descheduling succeeded.")
     return EXIT_OK
@@ -108,7 +108,7 @@ class Start(Verb):
     config = (context.get_job_config(context.options.jobspec, context.options.config)
         if context.options.config else None)
     resp = api.start_cronjob(context.options.jobspec, config=config)
-    context.check_and_log_response(resp,
+    context.log_response_and_raise(resp,
         err_msg=("Error starting cron job %s:" % context.options.jobspec))
     if context.options.open_browser:
       context.open_job_page(api, context.options.job_spec)
@@ -132,7 +132,7 @@ class Show(Verb):
     jobkey = context.options.jobspec
     api = context.get_api(jobkey.cluster)
     resp = api.get_jobs(jobkey.role)
-    context.check_and_log_response(resp, err_code=EXIT_INVALID_PARAMETER,
+    context.log_response_and_raise(resp, err_code=EXIT_INVALID_PARAMETER,
         err_msg=("Error getting cron status for %self from server" % jobkey))
     for job in resp.result.getJobsResult.configs:
       if job.key.environment == jobkey.env and job.key.name == jobkey.name:

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/main/python/apache/aurora/client/cli/jobs.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/jobs.py b/src/main/python/apache/aurora/client/cli/jobs.py
index 744d534..e65c80b 100644
--- a/src/main/python/apache/aurora/client/cli/jobs.py
+++ b/src/main/python/apache/aurora/client/cli/jobs.py
@@ -93,7 +93,7 @@ class CancelUpdateCommand(Verb):
     config = (context.get_job_config(context.options.jobspec, context.options.config_file)
         if context.options.config_file else None)
     resp = api.cancel_update(context.options.jobspec, config=config)
-    context.check_and_log_response(resp)
+    context.log_response_and_raise(resp)
     return EXIT_OK
 
 
@@ -126,7 +126,7 @@ class CreateJobCommand(Verb):
 
     api = context.get_api(config.cluster())
     resp = api.create_job(config)
-    context.check_and_log_response(resp, err_code=EXIT_COMMAND_FAILURE,
+    context.log_response_and_raise(resp, err_code=EXIT_COMMAND_FAILURE,
                                    err_msg="Job creation failed due to error:")
     if context.options.open_browser:
       context.open_job_page(api, context.options.jobspec)
@@ -142,7 +142,7 @@ class CreateJobCommand(Verb):
       context.print_err("Error occurred while creating job %s" % context.options.jobspec)
       return EXIT_COMMAND_FAILURE
     else:
-      context.print_out("job create succeeded: job url=%s" %
+      context.print_out("Job create succeeded: job url=%s" %
                         context.get_job_page(api, context.options.jobspec))
     return EXIT_OK
 
@@ -199,7 +199,7 @@ class DiffCommand(Verb):
       name = config.name()
     api = context.get_api(cluster)
     resp = api.query(api.build_query(role, name, statuses=ACTIVE_STATES, env=env))
-    context.check_and_log_response(resp, err_code=EXIT_INVALID_PARAMETER,
+    context.log_response_and_raise(resp, err_code=EXIT_INVALID_PARAMETER,
         err_msg="Could not find job to diff against")
     if resp.result.scheduleStatusResult.tasks is None:
       context.print_err("No tasks found for job %s" % context.options.jobspec)
@@ -207,7 +207,7 @@ class DiffCommand(Verb):
     else:
       remote_tasks = [t.assignedTask.task for t in resp.result.scheduleStatusResult.tasks]
     resp = api.populate_job_config(config)
-    context.check_and_log_response(resp, err_code=EXIT_INVALID_CONFIGURATION,
+    context.log_response_and_raise(resp, err_code=EXIT_INVALID_CONFIGURATION,
           err_msg="Error loading configuration")
     # Deepcopy is important here as tasks will be modified for printing.
     local_tasks = [deepcopy(get_populated_task_config(resp)) for _ in range(config.instances())]
@@ -311,7 +311,7 @@ class AbstractKillCommand(Verb):
   def wait_kill_tasks(self, context, scheduler, job_key, instances=None):
     monitor = JobMonitor(scheduler, job_key)
     if not monitor.wait_until(JobMonitor.terminal, instances=instances, with_timeout=True):
-      context.print_err("Tasks were not killed in time.")
+      context.print_err("Instances %s were not killed in time" % instances)
       return EXIT_TIMEOUT
     return EXIT_OK
 
@@ -333,22 +333,19 @@ class AbstractKillCommand(Verb):
       for i in range(min(context.options.batch_size, len(instances_to_kill))):
         batch.append(instances_to_kill.pop())
       resp = api.kill_job(job, batch)
-      if resp.responseCode == ResponseCode.LOCK_ERROR:
-        # Short circuit max errors in this case, and be sure to show the lock error message.
-        context.check_and_log_response(resp)
-      elif (resp.responseCode != ResponseCode.OK
-            or self.wait_kill_tasks(context, api.scheduler_proxy, job, batch) != EXIT_OK):
-        context.print_err("Kill of shards %s failed with error:" % batch)
-        context.log_response(resp)
+      # Short circuit max errors in this case as it's most likely a fatal repeatable error.
+      context.log_response_and_raise(
+        resp,
+        err_msg="Kill of instances %s failed with error:" % batch)
+
+      if self.wait_kill_tasks(context, api.scheduler_proxy, job, batch) != EXIT_OK:
         errors += 1
         if errors > context.options.max_total_failures:
-          context.print_err("Exceeded maximum number of errors while killing instances")
           raise context.CommandError(EXIT_COMMAND_FAILURE,
                "Exceeded maximum number of errors while killing instances")
       else:
-        context.print_out("Successfully killed shards %s" % batch)
+        context.print_out("Successfully killed instances %s" % batch)
     if errors > 0:
-      context.print_err("Warning: Errors occurred during batch kill")
       raise context.CommandError(EXIT_COMMAND_FAILURE, "Errors occurred while killing instances")
 
 
@@ -376,7 +373,7 @@ class KillCommand(AbstractKillCommand):
     api = context.get_api(job.cluster)
     if context.options.no_batching:
       resp = api.kill_job(job, instances_arg)
-      context.check_and_log_response(resp)
+      context.log_response_and_raise(resp)
       wait_result = self.wait_kill_tasks(context, api.scheduler_proxy, job, instances_arg)
       if wait_result is not EXIT_OK:
         return wait_result
@@ -384,7 +381,7 @@ class KillCommand(AbstractKillCommand):
       self.kill_in_batches(context, job, instances_arg)
     if context.options.open_browser:
       context.open_job_page(api, context.options.jobspec)
-    context.print_out("job kill succeeded")
+    context.print_out("Job kill succeeded")
     return EXIT_OK
 
 
@@ -405,7 +402,7 @@ class KillAllJobCommand(AbstractKillCommand):
     api = context.get_api(job.cluster)
     if context.options.no_batching:
       resp = api.kill_job(job, None)
-      context.check_and_log_response(resp)
+      context.log_response_and_raise(resp)
       wait_result = self.wait_kill_tasks(context, api.scheduler_proxy, job)
       if wait_result is not EXIT_OK:
         return wait_result
@@ -413,7 +410,7 @@ class KillAllJobCommand(AbstractKillCommand):
       self.kill_in_batches(context, job, None)
     if context.options.open_browser:
       context.open_job_page(api, job)
-    context.print_out("job killall succeeded")
+    context.print_out("Job killall succeeded")
     return EXIT_OK
 
 
@@ -514,7 +511,7 @@ class RestartCommand(Verb):
     resp = api.restart(job, instances, updater_config,
         context.options.healthcheck_interval_seconds, config=config)
 
-    context.check_and_log_response(resp,
+    context.log_response_and_raise(resp,
                                    err_msg="Error restarting job %s:" % str(job))
     context.print_out("Job %s restarted successfully" % str(job))
     if context.options.open_browser:
@@ -692,7 +689,7 @@ class UpdateCommand(Verb):
     # dangerous about this update.
     resp = api.query_no_configs(api.build_query(config.role(), config.name(),
         statuses=ACTIVE_STATES, env=config.environment()))
-    context.check_and_log_response(resp, err_msg="Server could not find running job to update")
+    context.log_response_and_raise(resp, err_msg="Server could not find running job to update")
     remote_tasks = [t.assignedTask.task for t in resp.result.scheduleStatusResult.tasks]
     # for determining if an update is dangerous, we estimate the scope of the change
     # by comparing number of instances to be updated, with the number of
@@ -726,7 +723,7 @@ class UpdateCommand(Verb):
       self.warn_if_dangerous_change(context, api, job, config)
     resp = api.update_job(config, context.options.healthcheck_interval_seconds,
         instances)
-    context.check_and_log_response(resp, err_code=EXIT_COMMAND_FAILURE,
+    context.log_response_and_raise(resp, err_code=EXIT_COMMAND_FAILURE,
         err_msg="Update failed due to error:")
     context.print_out("Update completed successfully")
     return EXIT_OK

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/main/python/apache/aurora/client/cli/quota.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/quota.py b/src/main/python/apache/aurora/client/cli/quota.py
index 137aab1..e8aa010 100644
--- a/src/main/python/apache/aurora/client/cli/quota.py
+++ b/src/main/python/apache/aurora/client/cli/quota.py
@@ -17,18 +17,10 @@ from __future__ import print_function
 from thrift.protocol import TJSONProtocol
 from thrift.TSerialization import serialize
 
-from apache.aurora.client.cli import (
-    EXIT_COMMAND_FAILURE,
-    EXIT_INVALID_PARAMETER,
-    EXIT_OK,
-    Noun,
-    Verb
-)
+from apache.aurora.client.cli import EXIT_OK, Noun, Verb
 from apache.aurora.client.cli.context import AuroraCommandContext
 from apache.aurora.client.cli.options import JSON_WRITE_OPTION, ROLE_ARGUMENT
 
-from gen.apache.aurora.api.ttypes import ResponseCode
-
 
 class GetQuotaCmd(Verb):
   @property
@@ -76,14 +68,10 @@ class GetQuotaCmd(Verb):
     (cluster, role) = context.options.role
     api = context.get_api(cluster)
     resp = api.get_quota(role)
-    context.log_response(resp)
-    if resp.responseCode == ResponseCode.ERROR:
-      raise context.CommandError(EXIT_INVALID_PARAMETER, 'Role %s not found' % role)
-    elif resp.responseCode == ResponseCode.INVALID_REQUEST:
-      raise context.CommandError(EXIT_COMMAND_FAILURE, 'Error retrieving quota for role %s'
% role)
-    elif resp.responseCode == ResponseCode.AUTH_FAILED:
-      raise context.CommandError(EXIT_COMMAND_FAILURE,
-          'Invalid authorization to retrieve quota for role %s' % role)
+    context.log_response_and_raise(
+        resp,
+        err_msg='Error retrieving quota for role %s' % role)
+
     context.print_out(self.render_quota(context.options.write_json, resp))
     return EXIT_OK
 

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/main/python/apache/aurora/client/cli/task.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/task.py b/src/main/python/apache/aurora/client/cli/task.py
index a70f908..e084c5b 100644
--- a/src/main/python/apache/aurora/client/cli/task.py
+++ b/src/main/python/apache/aurora/client/cli/task.py
@@ -104,7 +104,7 @@ class SshCommand(Verb):
 
     api = context.get_api(cluster)
     resp = api.query(api.build_query(role, name, set([int(instance)]), env=env))
-    context.check_and_log_response(resp,
+    context.log_response_and_raise(resp,
         err_msg=('Unable to get information about instance: %s' % combine_messages(resp)))
     if (resp.result.scheduleStatusResult.tasks is None or
         len(resp.result.scheduleStatusResult.tasks) == 0):

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/main/python/apache/aurora/client/cli/update.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/update.py b/src/main/python/apache/aurora/client/cli/update.py
index d1d0b29..fa0f00d 100644
--- a/src/main/python/apache/aurora/client/cli/update.py
+++ b/src/main/python/apache/aurora/client/cli/update.py
@@ -17,6 +17,7 @@ from __future__ import print_function
 import json
 import textwrap
 
+from apache.aurora.client.base import combine_messages
 from apache.aurora.client.cli import EXIT_API_ERROR, EXIT_COMMAND_FAILURE, EXIT_OK, Noun,
Verb
 from apache.aurora.client.cli.context import AuroraCommandContext
 from apache.aurora.client.cli.options import (
@@ -81,14 +82,14 @@ class StartUpdate(Verb):
 
     api = context.get_api(config.cluster())
     resp = api.start_job_update(config, instances)
-    context.check_and_log_response(resp, err_code=EXIT_API_ERROR,
+    context.log_response_and_raise(resp, err_code=EXIT_API_ERROR,
         err_msg="Failed to start update due to error:")
 
     if resp.result:
       url = context.get_update_page(api, job, resp.result.startJobUpdateResult.updateId)
       context.print_out(self.UPDATE_MSG_TEMPLATE % url)
     else:
-      context.print_out_response_details(resp)
+      context.print_out(combine_messages(resp))
     return EXIT_OK
 
 
@@ -110,7 +111,7 @@ class PauseUpdate(Verb):
     jobkey = context.options.jobspec
     api = context.get_api(jobkey.cluster)
     resp = api.pause_job_update(jobkey)
-    context.check_and_log_response(resp, err_code=EXIT_API_ERROR,
+    context.log_response_and_raise(resp, err_code=EXIT_API_ERROR,
       err_msg="Failed to pause update due to error:")
     context.print_out("Update has been paused.")
     return EXIT_OK
@@ -134,7 +135,7 @@ class ResumeUpdate(Verb):
     jobkey = context.options.jobspec
     api = context.get_api(jobkey.cluster)
     resp = api.resume_job_update(jobkey)
-    context.check_and_log_response(resp, err_code=EXIT_API_ERROR,
+    context.log_response_and_raise(resp, err_code=EXIT_API_ERROR,
       err_msg="Failed to resume update due to error:")
     context.print_out("Update has been resumed.")
     return EXIT_OK
@@ -158,7 +159,7 @@ class AbortUpdate(Verb):
     jobkey = context.options.jobspec
     api = context.get_api(jobkey.cluster)
     resp = api.abort_job_update(jobkey)
-    context.check_and_log_response(resp, err_code=EXIT_API_ERROR,
+    context.log_response_and_raise(resp, err_code=EXIT_API_ERROR,
       err_msg="Failed to abort update due to error:")
     context.print_out("Update has been aborted.")
     return EXIT_OK
@@ -196,7 +197,7 @@ class ListUpdates(Verb):
         job_key=context.options.jobspec,
         user=context.options.user,
         update_statuses=context.options.status)
-    context.check_and_log_response(response)
+    context.log_response_and_raise(response)
     if context.options.write_json:
       result = []
       for summary in response.result.getJobUpdateSummariesResult.updateSummaries:
@@ -238,7 +239,7 @@ class UpdateStatus(Verb):
   def _get_update_id(self, context, jobkey):
     api = context.get_api(context.options.jobspec.cluster)
     response = api.query_job_updates(job_key=context.options.jobspec)
-    context.check_and_log_response(response, "")
+    context.log_response_and_raise(response)
     for summary in response.result.getJobUpdateSummariesResult.updateSummaries:
       if summary.jobKey == jobkey:
         return summary.updateId
@@ -249,7 +250,7 @@ class UpdateStatus(Verb):
     id = self._get_update_id(context, context.options.jobspec)
     api = context.get_api(context.options.jobspec.cluster)
     response = api.get_job_update_details(id)
-    context.check_and_log_response(response)
+    context.log_response_and_raise(response)
     details = response.result.getJobUpdateDetailsResult.details
     if context.options.write_json:
       result = {}

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/test/python/apache/aurora/client/cli/test_create.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_create.py b/src/test/python/apache/aurora/client/cli/test_create.py
index 9aaf82a..18b5838 100644
--- a/src/test/python/apache/aurora/client/cli/test_create.py
+++ b/src/test/python/apache/aurora/client/cli/test_create.py
@@ -13,7 +13,6 @@
 #
 
 import contextlib
-import unittest
 
 import pytest
 from mock import create_autospec, Mock, patch
@@ -32,7 +31,12 @@ from apache.aurora.client.cli.jobs import CreateJobCommand
 from apache.aurora.common.aurora_job_key import AuroraJobKey
 from apache.aurora.config import AuroraConfig
 
-from .util import AuroraClientCommandTest, FakeAuroraCommandContext, mock_verb_options
+from .util import (
+    AuroraClientCommandTest,
+    FakeAuroraCommandContext,
+    FakeAuroraCommandLine,
+    mock_verb_options
+)
 
 from gen.apache.aurora.api.ttypes import (
     AssignedTask,
@@ -51,7 +55,7 @@ class UnknownException(Exception):
   pass
 
 
-class TestCreateJobCommand(unittest.TestCase):
+class TestCreateJobCommand(AuroraClientCommandTest):
 
   def test_create_with_lock(self):
     command = CreateJobCommand()
@@ -78,7 +82,7 @@ class TestCreateJobCommand(unittest.TestCase):
       command.execute(fake_context)
 
     mock_api.create_job.assert_called_once_with(mock_config)
-    assert fake_context.get_err()[0] == fake_context.LOCK_ERROR_MSG
+    self.assert_lock_message(fake_context)
 
 
 class TestClientCreateCommand(AuroraClientCommandTest):
@@ -315,7 +319,7 @@ class TestClientCreateCommand(AuroraClientCommandTest):
             fp.name])
         assert result == EXIT_OK
       assert mock_context.get_out() == [
-          "job create succeeded: job url=http://something_or_other/scheduler/bozo/test/hello"]
+          "Job create succeeded: job url=http://something_or_other/scheduler/bozo/test/hello"]
       assert mock_context.get_err() == []
 
   def test_create_job_startup_fails(self):
@@ -405,24 +409,23 @@ class TestClientCreateCommand(AuroraClientCommandTest):
     Verifies that the creation command sends the right API RPCs, and performs the correct
     tests on the result."""
 
-    mock_context = FakeAuroraCommandContext()
     with contextlib.nested(
-        patch('threading._Event.wait'),
-        patch('apache.aurora.client.cli.jobs.Job.create_context', return_value=mock_context)):
+        patch('threading._Event.wait')):
 
       # This is the real test: invoke create as if it had been called by the command line.
       with temporary_file() as fp:
         fp.write(self.get_unbound_test_config())
         fp.flush()
-        cmd = AuroraCommandLine()
+        cmd = FakeAuroraCommandLine()
         result = cmd.execute(['job', 'create', '--wait-until=RUNNING',
             '--bind', 'cluster_binding=west',
            'west/bozo/test/hello',
             fp.name])
         assert result == EXIT_INVALID_CONFIGURATION
-      assert mock_context.get_err() == [
-          "TypeCheck(FAILED): MesosJob[update_config] failed: "
-          "UpdateConfig[batch_size] failed: u'{{TEST_BATCH}}' not an integer"]
+        assert cmd.get_err() == [
+            "Error executing command: Error loading configuration: "
+            "TypeCheck(FAILED): MesosJob[update_config] failed: "
+            "UpdateConfig[batch_size] failed: u'{{TEST_BATCH}}' not an integer"]
 
   def test_create_cron_job_fails(self):
     """Test a cron job is not accepted."""

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/test/python/apache/aurora/client/cli/test_kill.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_kill.py b/src/test/python/apache/aurora/client/cli/test_kill.py
index 3036f9c..b475d73 100644
--- a/src/test/python/apache/aurora/client/cli/test_kill.py
+++ b/src/test/python/apache/aurora/client/cli/test_kill.py
@@ -26,7 +26,12 @@ from apache.aurora.client.cli.jobs import KillCommand
 from apache.aurora.client.cli.options import parse_instances, TaskInstanceKey
 from apache.aurora.common.aurora_job_key import AuroraJobKey
 
-from .util import AuroraClientCommandTest, FakeAuroraCommandContext, mock_verb_options
+from .util import (
+    AuroraClientCommandTest,
+    FakeAuroraCommandContext,
+    FakeAuroraCommandLine,
+    mock_verb_options
+)
 
 from gen.apache.aurora.api.ttypes import (
     JobKey,
@@ -49,7 +54,7 @@ class TestInstancesParser(unittest.TestCase):
     assert parse_instances("") is None
 
 
-class TestKillCommand(unittest.TestCase):
+class TestKillCommand(AuroraClientCommandTest):
 
   def test_kill_lock_error_nobatch(self):
     """Verify that the no batch code path correctly includes the lock error message."""
@@ -72,7 +77,7 @@ class TestKillCommand(unittest.TestCase):
       command.execute(fake_context)
 
     mock_api.kill_job.assert_called_once_with(jobkey, mock_options.instance_spec.instance)
-    assert fake_context.get_err()[0] == fake_context.LOCK_ERROR_MSG
+    self.assert_lock_message(fake_context)
 
   def test_kill_lock_error_batches(self):
     """Verify that the batch kill path short circuits and includes the lock error message."""
@@ -99,7 +104,7 @@ class TestKillCommand(unittest.TestCase):
       command.execute(fake_context)
 
     mock_api.kill_job.assert_called_once_with(jobkey, mock_options.instance_spec.instance)
-    assert fake_context.get_err()[0] == fake_context.LOCK_ERROR_MSG
+    self.assert_lock_message(fake_context)
 
 
 class TestClientKillCommand(AuroraClientCommandTest):
@@ -113,9 +118,9 @@ class TestClientKillCommand(AuroraClientCommandTest):
                                      name=cls.TEST_JOB)])
 
   @classmethod
-  def get_monitor_mock(cls):
+  def get_monitor_mock(cls, result=True):
     mock_monitor = Mock(spec=JobMonitor)
-    mock_monitor.wait_until.return_value = True
+    mock_monitor.wait_until.return_value = result
     return mock_monitor
 
   @classmethod
@@ -275,12 +280,14 @@ class TestClientKillCommand(AuroraClientCommandTest):
   def test_kill_job_with_instances_batched_maxerrors(self):
     """Test kill client-side API logic."""
     mock_context = FakeAuroraCommandContext()
+    mock_monitor = self.get_monitor_mock(result=False)
     with contextlib.nested(
         patch('apache.aurora.client.cli.jobs.Job.create_context', return_value=mock_context),
+        patch('apache.aurora.client.cli.jobs.JobMonitor', return_value=mock_monitor),
         patch('apache.aurora.client.factory.CLUSTERS', new=self.TEST_CLUSTERS)):
       api = mock_context.get_api('west')
       mock_context.add_expected_status_query_result(self.create_status_call_result())
-      api.kill_job.return_value = self.create_error_response()
+      api.kill_job.return_value = self.create_simple_success_response()
 
       with temporary_file() as fp:
         fp.write(self.get_valid_config())
@@ -330,7 +337,7 @@ class TestClientKillCommand(AuroraClientCommandTest):
         cmd = AuroraCommandLine()
         cmd.execute(['job', 'killall', '--no-batching', '--config=%s' % fp.name, self.TEST_JOBSPEC])
 
-      assert mock_context.get_out() == ['job killall succeeded']
+      assert mock_context.get_out() == ['Job killall succeeded']
       assert mock_context.get_err() == []
 
   def test_kill_job_with_instances_batched_output(self):
@@ -351,30 +358,33 @@ class TestClientKillCommand(AuroraClientCommandTest):
         cmd.execute(['job', 'kill', '--config=%s' % fp.name, '--batch-size=5',
                      self.get_instance_spec('0,2,4-6')])
 
-    assert mock_context.get_out() == ['Successfully killed shards [0, 2, 4, 5, 6]',
-        'job kill succeeded']
+    assert mock_context.get_out() == ['Successfully killed instances [0, 2, 4, 5, 6]',
+        'Job kill succeeded']
     assert mock_context.get_err() == []
 
   def test_kill_job_with_instances_batched_maxerrors_output(self):
     """Test kill client-side API logic."""
     mock_context = FakeAuroraCommandContext()
+    mock_monitor = self.get_monitor_mock(result=False)
     with contextlib.nested(
         patch('apache.aurora.client.cli.jobs.Job.create_context', return_value=mock_context),
-        patch('apache.aurora.client.cli.jobs.JobMonitor', return_value=self.get_monitor_mock()),
+        patch('apache.aurora.client.cli.jobs.JobMonitor', return_value=mock_monitor),
         patch('apache.aurora.client.factory.CLUSTERS', new=self.TEST_CLUSTERS)):
       api = mock_context.get_api('west')
       mock_context.add_expected_status_query_result(self.create_status_call_result())
-      api.kill_job.return_value = self.create_error_response()
+      api.kill_job.return_value = self.create_simple_success_response()
 
       with temporary_file() as fp:
         fp.write(self.get_valid_config())
         fp.flush()
-        cmd = AuroraCommandLine()
+        cmd = FakeAuroraCommandLine()
         cmd.execute(['job', 'kill', '--max-total-failures=1', '--config=%s' % fp.name,
                      '--batch-size=5', self.get_instance_spec('0,2,4-13')])
 
       assert mock_context.get_out() == []
       assert mock_context.get_err() == [
-         'Kill of shards [0, 2, 4, 5, 6] failed with error:', '\tDamn',
-         'Kill of shards [7, 8, 9, 10, 11] failed with error:', '\tDamn',
-         'Exceeded maximum number of errors while killing instances']
+         'Instances [0, 2, 4, 5, 6] were not killed in time',
+         'Instances [7, 8, 9, 10, 11] were not killed in time']
+
+      assert cmd.get_err() == [
+        'Error executing command: Exceeded maximum number of errors while killing instances']

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/test/python/apache/aurora/client/cli/test_quota.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_quota.py b/src/test/python/apache/aurora/client/cli/test_quota.py
index 202cc45..c8d217d 100644
--- a/src/test/python/apache/aurora/client/cli/test_quota.py
+++ b/src/test/python/apache/aurora/client/cli/test_quota.py
@@ -70,6 +70,15 @@ class TestGetQuotaCommand(AuroraClientCommandTest):
     assert (expected_response ==
             json.loads(self._get_quota(True, ['quota', 'get', '--write-json', 'west/bozo'])))
 
+  def test_get_quota_failed(self):
+    fake_context = FakeAuroraCommandContext()
+    api = fake_context.get_api('')
+    api.get_quota.return_value = self.create_error_response()
+
+    self._call_get_quota(fake_context, ['quota', 'get', 'west/bozo'])
+
+    assert fake_context.get_err() == ['Error retrieving quota for role bozo', '\tDamn']
+
   def _get_quota(self, include_consumption, command_args):
     mock_context = FakeAuroraCommandContext()
     if include_consumption:
@@ -77,6 +86,9 @@ class TestGetQuotaCommand(AuroraClientCommandTest):
     else:
       self.setup_mock_quota_call_no_consumption(mock_context)
 
+    return self._call_get_quota(mock_context, command_args)
+
+  def _call_get_quota(self, mock_context, command_args):
     with contextlib.nested(
         patch('apache.aurora.client.cli.quota.Quota.create_context', return_value=mock_context),
         patch('apache.aurora.client.factory.CLUSTERS', new=self.TEST_CLUSTERS)):

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/test/python/apache/aurora/client/cli/test_restart.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_restart.py b/src/test/python/apache/aurora/client/cli/test_restart.py
index 1653ae2..a532ead 100644
--- a/src/test/python/apache/aurora/client/cli/test_restart.py
+++ b/src/test/python/apache/aurora/client/cli/test_restart.py
@@ -13,7 +13,6 @@
 #
 import contextlib
 import functools
-import unittest
 
 import pytest
 from mock import create_autospec, patch
@@ -32,7 +31,7 @@ from .util import AuroraClientCommandTest, FakeAuroraCommandContext, IOMock,
moc
 from gen.apache.aurora.api.ttypes import JobKey, PopulateJobResult, ResponseCode, Result,
TaskConfig
 
 
-class TestRestartJobCommand(unittest.TestCase):
+class TestRestartJobCommand(AuroraClientCommandTest):
 
   def test_restart_with_lock(self):
     command = RestartCommand()
@@ -61,7 +60,7 @@ class TestRestartJobCommand(unittest.TestCase):
 
     mock_api.restart.assert_called_once_with(jobkey, mock_options.instance_spec.instance,
       updater_config, mock_options.healthcheck_interval_seconds, config=None)
-    assert fake_context.get_err()[0] == fake_context.LOCK_ERROR_MSG
+    self.assert_lock_message(fake_context)
 
 
 class TestRestartCommand(AuroraClientCommandTest):

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/test/python/apache/aurora/client/cli/test_supdate.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_supdate.py b/src/test/python/apache/aurora/client/cli/test_supdate.py
index eafb909..9378b49 100644
--- a/src/test/python/apache/aurora/client/cli/test_supdate.py
+++ b/src/test/python/apache/aurora/client/cli/test_supdate.py
@@ -13,7 +13,6 @@
 #
 import contextlib
 import textwrap
-import unittest
 
 import pytest
 from mock import create_autospec, Mock, patch
@@ -47,7 +46,7 @@ from gen.apache.aurora.api.ttypes import (
 )
 
 
-class TestStartUpdateCommand(unittest.TestCase):
+class TestStartUpdateCommand(AuroraClientCommandTest):
 
   def setUp(self):
     self._command = StartUpdate()
@@ -80,7 +79,7 @@ class TestStartUpdateCommand(unittest.TestCase):
         mock_config,
         self._mock_options.instance_spec.instance)
 
-    assert self._fake_context.get_err()[0] == self._fake_context.LOCK_ERROR_MSG
+    self.assert_lock_message(self._fake_context)
 
   def test_update_cron_job_fails(self):
     mock_config = self.create_mock_config(is_cron=True)

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/test/python/apache/aurora/client/cli/test_update.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_update.py b/src/test/python/apache/aurora/client/cli/test_update.py
index 561dd96..c12b32e 100644
--- a/src/test/python/apache/aurora/client/cli/test_update.py
+++ b/src/test/python/apache/aurora/client/cli/test_update.py
@@ -80,7 +80,7 @@ class TestJobUpdateCommand(AuroraClientCommandTest):
       mock_config,
       self._mock_options.healthcheck_interval_seconds,
       self._mock_options.instance_spec.instance)
-    assert self._fake_context.get_err()[0] == self._fake_context.LOCK_ERROR_MSG
+    self.assert_lock_message(self._fake_context)
 
   def test_update_print_error_once(self):
     mock_config = self.create_mock_config()

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7449e34d/src/test/python/apache/aurora/client/cli/util.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/util.py b/src/test/python/apache/aurora/client/cli/util.py
index 6dba185..b51ca2f 100644
--- a/src/test/python/apache/aurora/client/cli/util.py
+++ b/src/test/python/apache/aurora/client/cli/util.py
@@ -17,6 +17,7 @@ import unittest
 
 from mock import create_autospec, Mock
 
+from apache.aurora.client.cli.client import AuroraCommandLine
 from apache.aurora.client.cli.context import AuroraCommandContext
 from apache.aurora.client.hooks.hooked_api import HookedAuroraClientAPI
 from apache.aurora.common.aurora_job_key import AuroraJobKey
@@ -56,6 +57,19 @@ def create_options_mock(options):
   return mock
 
 
+class FakeAuroraCommandLine(AuroraCommandLine):
+  def __init__(self):
+    super(FakeAuroraCommandLine, self).__init__()
+    self.__err = []
+
+  def print_err(self, s, indent=0):
+    indent_str = " " * indent
+    self.__err.append("%s%s" % (indent_str, s))
+
+  def get_err(self):
+    return self.__err
+
+
 class FakeAuroraCommandContext(AuroraCommandContext):
   def __init__(self):
     super(FakeAuroraCommandContext, self).__init__()
@@ -351,6 +365,10 @@ jobs = [HELLO_WORLD]
         cls.TEST_JOB,
         bad_clause)
 
+  @classmethod
+  def assert_lock_message(cls, context):
+    assert context.get_err()[2] == "\t%s" % context.LOCK_ERROR_MSG
+
 
 class IOMock(object):
   def __init__(self):


Mime
View raw message