aurora-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wfar...@apache.org
Subject aurora git commit: Don't retry API requests that fail with auth errors.
Date Mon, 04 May 2015 17:57:44 GMT
Repository: aurora
Updated Branches:
  refs/heads/master 181f38207 -> 9a2bbded5


Don't retry API requests that fail with auth errors.

Bugs closed: AURORA-1248

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


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

Branch: refs/heads/master
Commit: 9a2bbded5aeee78c74984d8aca84324ba66b0779
Parents: 181f382
Author: Bill Farner <wfarner@apache.org>
Authored: Mon May 4 10:57:28 2015 -0700
Committer: Bill Farner <wfarner@apache.org>
Committed: Mon May 4 10:57:28 2015 -0700

----------------------------------------------------------------------
 .../aurora/client/api/scheduler_client.py       |  8 ++-
 .../python/apache/aurora/client/cli/__init__.py |  1 +
 .../python/apache/aurora/client/cli/context.py  | 44 ++++++++++--
 .../python/apache/aurora/common/transport.py    | 18 +++--
 .../aurora/client/api/test_scheduler_client.py  | 76 +++++++++++---------
 .../apache/aurora/client/cli/test_context.py    | 31 +++++++-
 .../apache/aurora/common/test_transport.py      | 28 ++++++--
 .../sh/org/apache/aurora/e2e/test_end_to_end.sh | 26 ++++---
 8 files changed, 165 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aurora/blob/9a2bbded/src/main/python/apache/aurora/client/api/scheduler_client.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/api/scheduler_client.py b/src/main/python/apache/aurora/client/api/scheduler_client.py
index 3f9c691..2b8047c 100644
--- a/src/main/python/apache/aurora/client/api/scheduler_client.py
+++ b/src/main/python/apache/aurora/client/api/scheduler_client.py
@@ -214,7 +214,7 @@ class SchedulerProxy(object):
   class Error(Exception): pass
   class TimeoutError(Error): pass
   class TransientError(Error): pass
-  class AuthenticationError(Error): pass
+  class AuthError(Error): pass
   class APIVersionError(Error): pass
   class ThriftInternalError(Error): pass
 
@@ -258,7 +258,7 @@ class SchedulerProxy(object):
     try:
       return self._session_key_factory(self.cluster.auth_mechanism)
     except SessionKeyError as e:
-      raise self.AuthenticationError('Unable to create session key %s' % e)
+      raise self.AuthError('Unable to create session key %s' % e)
 
   def _construct_scheduler(self):
     """
@@ -281,7 +281,7 @@ class SchedulerProxy(object):
         # turn any auth module exception into an auth error.
         log.debug('Warning: got an unknown exception during authentication:')
         log.debug(traceback.format_exc())
-        raise self.AuthenticationError('Error connecting to scheduler: %s' % e)
+        raise self.AuthError('Error connecting to scheduler: %s' % e)
     if not self._client:
       raise self.TimeoutError('Timed out trying to connect to scheduler at %s' % self.cluster.name)
 
@@ -313,6 +313,8 @@ class SchedulerProxy(object):
               raise self.APIVersionError("Client Version: %s, Server Version: %s" %
                   (THRIFT_API_VERSION, resp.serverInfo.thriftAPIVersion))
             return resp
+          except TRequestsTransport.AuthError as e:
+            raise self.AuthError(e)
           except (TTransport.TTransportException, self.TimeoutError, self.TransientError)
as e:
             if not self._terminating.is_set():
               log.warning('Connection error with scheduler: %s, reconnecting...' % e)

http://git-wip-us.apache.org/repos/asf/aurora/blob/9a2bbded/src/main/python/apache/aurora/client/cli/__init__.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/__init__.py b/src/main/python/apache/aurora/client/cli/__init__.py
index 10d9432..1208846 100644
--- a/src/main/python/apache/aurora/client/cli/__init__.py
+++ b/src/main/python/apache/aurora/client/cli/__init__.py
@@ -55,6 +55,7 @@ EXIT_NETWORK_ERROR = 7
 EXIT_TIMEOUT = 9
 EXIT_API_ERROR = 10
 EXIT_UNKNOWN_ERROR = 20
+EXIT_AUTH_ERROR = 30
 
 
 try:

http://git-wip-us.apache.org/repos/asf/aurora/blob/9a2bbded/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 adbffc4..146960e 100644
--- a/src/main/python/apache/aurora/client/cli/context.py
+++ b/src/main/python/apache/aurora/client/cli/context.py
@@ -14,14 +14,16 @@
 
 from __future__ import print_function
 
+import functools
 import logging
 from fnmatch import fnmatch
 
-from apache.aurora.client.api import AuroraClientAPI
+from apache.aurora.client.api import AuroraClientAPI, SchedulerProxy
 from apache.aurora.client.base import AURORA_V2_USER_AGENT_NAME, combine_messages
 from apache.aurora.client.cli import (
     Context,
     EXIT_API_ERROR,
+    EXIT_AUTH_ERROR,
     EXIT_COMMAND_FAILURE,
     EXIT_INVALID_CONFIGURATION,
     EXIT_INVALID_PARAMETER
@@ -31,10 +33,42 @@ from apache.aurora.client.hooks.hooked_api import HookedAuroraClientAPI
 from apache.aurora.common.aurora_job_key import AuroraJobKey
 from apache.aurora.common.clusters import CLUSTERS
 
+from gen.apache.aurora.api import AuroraAdmin
 from gen.apache.aurora.api.constants import ACTIVE_STATES
 from gen.apache.aurora.api.ttypes import ResponseCode
 
 
+class AuthErrorHandlingScheduler(object):
+  """A decorator that can be applied on a AuroraClientAPI instance to add handling of
+  auth-related errors, terminating the client."""
+
+  def __init__(self, delegate):
+    self._delegate = delegate
+
+  def __getattr__(self, method_name):
+    try:
+      method = getattr(AuroraAdmin.Client, method_name)
+    except AttributeError:
+      # Don't interfere with the non-public API.
+      return getattr(self._delegate, method_name)
+    if not callable(method):
+      return method
+
+    @functools.wraps(method)
+    def method_wrapper(*args, **kwargs):
+      try:
+        return getattr(self._delegate, method_name)(*args, **kwargs)
+      except SchedulerProxy.AuthError as e:
+        raise Context.CommandError(EXIT_AUTH_ERROR, str(e))
+
+    return method_wrapper
+
+
+def add_auth_error_handler(api):
+  api._scheduler_proxy = AuthErrorHandlingScheduler(api._scheduler_proxy)
+  return api
+
+
 class AuroraCommandContext(Context):
 
   LOCK_ERROR_MSG = """Error: job is locked by an incomplete update.
@@ -50,21 +84,21 @@ class AuroraCommandContext(Context):
     self.apis = {}
     self.unhooked_apis = {}
 
-  def get_api(self, cluster, enable_hooks=True):
+  def get_api(self, cluster, enable_hooks=True, clusters=CLUSTERS):
     """Gets an API object for a specified cluster
     Keeps the API handle cached, so that only one handle for each cluster will be created
in a
     session.
     """
-    if cluster not in CLUSTERS:
+    if cluster not in clusters:
       raise self.CommandError(EXIT_INVALID_CONFIGURATION, "Unknown cluster: %s" % cluster)
 
     apis = self.apis if enable_hooks else self.unhooked_apis
     base_class = HookedAuroraClientAPI if enable_hooks else AuroraClientAPI
 
     if cluster not in apis:
-      api = base_class(CLUSTERS[cluster], AURORA_V2_USER_AGENT_NAME, verbose=True)
+      api = base_class(clusters[cluster], AURORA_V2_USER_AGENT_NAME, verbose=True)
       apis[cluster] = api
-    return apis[cluster]
+    return add_auth_error_handler(apis[cluster])
 
   def get_job_config(self, jobkey, config_file):
     """Loads a job configuration from a config file."""

http://git-wip-us.apache.org/repos/asf/aurora/blob/9a2bbded/src/main/python/apache/aurora/common/transport.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/common/transport.py b/src/main/python/apache/aurora/common/transport.py
index eefe8f7..909021a 100644
--- a/src/main/python/apache/aurora/common/transport.py
+++ b/src/main/python/apache/aurora/common/transport.py
@@ -37,6 +37,10 @@ def default_requests_session_factory():
 class TRequestsTransport(TTransportBase):
   """A Thrift HTTP client based upon the requests module."""
 
+  class AuthError(Exception):
+    """Indicates that a request failed due to an authentication or authorization problem.
"""
+    pass
+
   def __init__(
       self,
       uri,
@@ -57,7 +61,7 @@ class TRequestsTransport(TTransportBase):
     :keyword auth: The requests authentication context
     :type auth: requests.auth.AuthBase
     :keyword session_factory: A callable that returns a requests session
-    :type session_factory: requests.Session
+    :type session_factory: () -> requests.Session
     :keyword user_agent: The value to use for the User-Agent header
     :type user_agent: str
     """
@@ -119,7 +123,6 @@ class TRequestsTransport(TTransportBase):
     self._session.headers['Content-Length'] = str(len(data))
     self._session.headers['Host'] = self.__urlparse.hostname
 
-    response = None
     try:
       response = self._session.post(
           self.__uri,
@@ -127,17 +130,18 @@ class TRequestsTransport(TTransportBase):
           timeout=self.__timeout,
           auth=self.__auth)
       response.raise_for_status()
+      self.__rbuf = BytesIO(response.content)
     except request_exceptions.Timeout:
       raise TTransportException(
           type=TTransportException.TIMED_OUT,
           message='Timed out talking to %s' % self.__uri)
     except request_exceptions.RequestException as e:
-      if response:
-        log.debug('Error connecting, logging response headers:.')
-        for field_name, field_value in response.headers.items():
+      if e.response is not None:
+        log.debug('Request failed, response headers:')
+        for field_name, field_value in e.response.headers.items():
           log.debug('  %s: %s' % (field_name, field_value))
+        if e.response.status_code in (401, 403):
+          raise self.AuthError(e)
       raise TTransportException(
           type=TTransportException.UNKNOWN,
           message='Unknown error talking to %s: %s' % (self.__uri, e))
-
-    self.__rbuf = BytesIO(response.content)

http://git-wip-us.apache.org/repos/asf/aurora/blob/9a2bbded/src/test/python/apache/aurora/client/api/test_scheduler_client.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/api/test_scheduler_client.py b/src/test/python/apache/aurora/client/api/test_scheduler_client.py
index 9319728..10e8ebb 100644
--- a/src/test/python/apache/aurora/client/api/test_scheduler_client.py
+++ b/src/test/python/apache/aurora/client/api/test_scheduler_client.py
@@ -67,15 +67,14 @@ def test_coverage():
           'No test defined for RPC %s' % rpc_name)
 
 
+SESSION = SessionKey(mechanism='test', data='test')
+
+
 class TestSchedulerProxy(scheduler_client.SchedulerProxy):
   """In testing we shouldn't use the real SSHAgentAuthenticator."""
 
   def session_key(self):
-    return self.create_session('SOME_USER')
-
-  @classmethod
-  def create_session(cls, user):
-    return SessionKey(mechanism='test', data='test')
+    return SESSION
 
 
 class TestSchedulerProxyInjection(unittest.TestCase):
@@ -100,14 +99,14 @@ class TestSchedulerProxyInjection(unittest.TestCase):
     return TestSchedulerProxy(Cluster(name='local'))
 
   def test_startCronJob(self):
-    self.mock_thrift_client.startCronJob(IsA(JobKey), IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.startCronJob(IsA(JobKey), SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().startCronJob(JOB_KEY)
 
   def test_createJob(self):
     self.mock_thrift_client.createJob(
         IsA(JobConfiguration),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().createJob(JobConfiguration())
 
@@ -115,21 +114,21 @@ class TestSchedulerProxyInjection(unittest.TestCase):
     self.mock_thrift_client.replaceCronTemplate(
         IsA(JobConfiguration),
         IsA(Lock),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().replaceCronTemplate(JobConfiguration(), Lock())
 
   def test_scheduleCronJob(self):
     self.mock_thrift_client.scheduleCronJob(
         IsA(JobConfiguration),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().scheduleCronJob(JobConfiguration())
 
   def test_descheduleCronJob(self):
     self.mock_thrift_client.descheduleCronJob(
         IsA(JobKey),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().descheduleCronJob(JOB_KEY)
 
@@ -142,7 +141,7 @@ class TestSchedulerProxyInjection(unittest.TestCase):
     self.mock_thrift_client.restartShards(
         IsA(JobKey),
         IgnoreArg(),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().restartShards(JOB_KEY, set([0]))
 
@@ -157,7 +156,7 @@ class TestSchedulerProxyInjection(unittest.TestCase):
     self.make_scheduler_proxy().getJobs(ROLE)
 
   def test_killTasks(self):
-    self.mock_thrift_client.killTasks(IsA(TaskQuery), IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.killTasks(IsA(TaskQuery), SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().killTasks(TaskQuery())
 
@@ -178,12 +177,12 @@ class TestSchedulerProxyInjection(unittest.TestCase):
       IsA(JobKey),
       IgnoreArg(),
       IsA(Lock),
-      IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+      SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().addInstances(JobKey(), {}, Lock())
 
   def test_acquireLock(self):
-    self.mock_thrift_client.acquireLock(IsA(Lock), IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.acquireLock(IsA(Lock), SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().acquireLock(Lock())
 
@@ -191,7 +190,7 @@ class TestSchedulerProxyInjection(unittest.TestCase):
     self.mock_thrift_client.releaseLock(
         IsA(Lock),
         IsA(LockValidation),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().releaseLock(Lock(), LockValidation())
 
@@ -208,55 +207,62 @@ class TestSchedulerProxyInjection(unittest.TestCase):
   def test_startJobUpdate(self):
     self.mock_thrift_client.startJobUpdate(
         IsA(JobUpdateRequest),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().startJobUpdate(JobUpdateRequest())
 
   def test_pauseJobUpdate(self):
-    self.mock_thrift_client.pauseJobUpdate('update_id', IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.pauseJobUpdate('update_id', SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().pauseJobUpdate('update_id')
 
   def test_resumeJobUpdate(self):
     self.mock_thrift_client.resumeJobUpdate(
         'update_id',
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().resumeJobUpdate('update_id')
 
   def test_abortJobUpdate(self):
-    self.mock_thrift_client.abortJobUpdate('update_id', IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.abortJobUpdate('update_id', SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().abortJobUpdate('update_id')
 
   def test_pulseJobUpdate(self):
-    self.mock_thrift_client.pulseJobUpdate('update_id', IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.pulseJobUpdate('update_id', SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().pulseJobUpdate('update_id')
 
+  def test_raise_auth_error(self):
+    self.mock_thrift_client.killTasks(TaskQuery(), None, None, SESSION).AndRaise(
+        TRequestsTransport.AuthError())
+    self.mox.ReplayAll()
+    with pytest.raises(scheduler_client.SchedulerProxy.AuthError):
+      self.make_scheduler_proxy().killTasks(TaskQuery(), None, None)
+
 
 class TestSchedulerProxyAdminInjection(TestSchedulerProxyInjection):
   def test_startMaintenance(self):
     self.mock_thrift_client.startMaintenance(
       IsA(Hosts),
-      IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+      SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().startMaintenance(Hosts())
 
   def test_drainHosts(self):
-    self.mock_thrift_client.drainHosts(IsA(Hosts), IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.drainHosts(IsA(Hosts), SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().drainHosts(Hosts())
 
   def test_maintenanceStatus(self):
     self.mock_thrift_client.maintenanceStatus(
       IsA(Hosts),
-      IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+      SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().maintenanceStatus(Hosts())
 
   def test_endMaintenance(self):
-    self.mock_thrift_client.endMaintenance(IsA(Hosts), IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.endMaintenance(IsA(Hosts), SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().endMaintenance(Hosts())
 
@@ -264,7 +270,7 @@ class TestSchedulerProxyAdminInjection(TestSchedulerProxyInjection):
     self.mock_thrift_client.setQuota(
         IgnoreArg(),
         IsA(ResourceAggregate),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().setQuota(ROLE, ResourceAggregate())
 
@@ -272,60 +278,60 @@ class TestSchedulerProxyAdminInjection(TestSchedulerProxyInjection):
     self.mock_thrift_client.forceTaskState(
         'taskid',
         IgnoreArg(),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().forceTaskState('taskid', ScheduleStatus.LOST)
 
   def test_performBackup(self):
-    self.mock_thrift_client.performBackup(IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.performBackup(SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().performBackup()
 
   def test_listBackups(self):
-    self.mock_thrift_client.listBackups(IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.listBackups(SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().listBackups()
 
   def test_stageRecovery(self):
     self.mock_thrift_client.stageRecovery(
         IsA(TaskQuery),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().stageRecovery(TaskQuery())
 
   def test_queryRecovery(self):
     self.mock_thrift_client.queryRecovery(
       IsA(TaskQuery),
-      IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+      SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().queryRecovery(TaskQuery())
 
   def test_deleteRecoveryTasks(self):
     self.mock_thrift_client.deleteRecoveryTasks(
         IsA(TaskQuery),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().deleteRecoveryTasks(TaskQuery())
 
   def test_commitRecovery(self):
-    self.mock_thrift_client.commitRecovery(IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.commitRecovery(SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().commitRecovery()
 
   def test_unloadRecovery(self):
-    self.mock_thrift_client.unloadRecovery(IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.unloadRecovery(SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().unloadRecovery()
 
   def test_snapshot(self):
-    self.mock_thrift_client.snapshot(IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+    self.mock_thrift_client.snapshot(SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().snapshot()
 
   def test_rewriteConfigs(self):
     self.mock_thrift_client.rewriteConfigs(
         IsA(RewriteConfigsRequest),
-        IsA(SessionKey)).AndReturn(DEFAULT_RESPONSE)
+        SESSION).AndReturn(DEFAULT_RESPONSE)
     self.mox.ReplayAll()
     self.make_scheduler_proxy().rewriteConfigs(RewriteConfigsRequest())
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/9a2bbded/src/test/python/apache/aurora/client/cli/test_context.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_context.py b/src/test/python/apache/aurora/client/cli/test_context.py
index d63f060..1a134a2 100644
--- a/src/test/python/apache/aurora/client/cli/test_context.py
+++ b/src/test/python/apache/aurora/client/cli/test_context.py
@@ -11,14 +11,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+import mock
+import pytest
 
-from apache.aurora.client.api import AuroraClientAPI
+from apache.aurora.client.api import AuroraClientAPI, SchedulerProxy
+from apache.aurora.client.cli import Context, EXIT_AUTH_ERROR
 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
 from apache.aurora.common.cluster import Cluster
 from apache.aurora.common.clusters import CLUSTERS
 
-TEST_CLUSTER = Cluster(name='some-cluster')
+from ...api_util import SchedulerProxyApiSpec
+
+TEST_CLUSTER = Cluster(name='some-cluster', auth_mechanism='nothing', scheduler_uri='nowhere')
 
 
 def test_get_api_defaults_to_hooks_enabled():
@@ -48,3 +54,24 @@ def test_get_api_caches_hook_enabled_apis_separately():
 
     assert unhooked_api in context.unhooked_apis.values()
     assert unhooked_api not in context.apis.values()
+
+
+def test_handles_api_auth_error():
+  context = AuroraCommandContext()
+
+  mock_scheduler_proxy = mock.create_autospec(spec=SchedulerProxyApiSpec, instance=True)
+  mock_scheduler_proxy.killTasks.side_effect = SchedulerProxy.AuthError()
+
+  mock_api = AuroraClientAPI(TEST_CLUSTER, 'user-agent')
+  mock_api._scheduler_proxy = mock_scheduler_proxy
+
+  context.apis = {
+    TEST_CLUSTER.name: mock_api
+  }
+  api = context.get_api(TEST_CLUSTER.name, clusters={TEST_CLUSTER.name: TEST_CLUSTER})
+
+  with pytest.raises(Context.CommandError) as e:
+    api.kill_job(AuroraJobKey(TEST_CLUSTER.name, 'role', 'env', 'job'))
+
+  assert e.value.code == EXIT_AUTH_ERROR
+  assert mock_scheduler_proxy.killTasks.call_count == 1

http://git-wip-us.apache.org/repos/asf/aurora/blob/9a2bbded/src/test/python/apache/aurora/common/test_transport.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/common/test_transport.py b/src/test/python/apache/aurora/common/test_transport.py
index e4f93ef..f307e8d 100644
--- a/src/test/python/apache/aurora/common/test_transport.py
+++ b/src/test/python/apache/aurora/common/test_transport.py
@@ -77,9 +77,8 @@ def test_request_transport_timeout():
 
 
 def test_raise_for_status_causes_exception():
-  response = create_autospec(spec=requests.Response, instance=True)
-  response.headers = {'header1': 'data', 'header2': 'data2'}
-  response.raise_for_status.side_effect = requests.exceptions.HTTPError()
+  response = requests.Response()
+  response.status_code = 503
 
   session = create_autospec(spec=requests.Session, instance=True)
   session.headers = {}
@@ -97,7 +96,23 @@ def test_raise_for_status_causes_exception():
 
   transport.close()
 
-  response.raise_for_status.assert_called_once_with()
+
+def test_raises_auth_error():
+  response = requests.Response()
+  response.status_code = 401
+
+  session = create_autospec(spec=requests.Session, instance=True)
+  session.headers = {}
+  session.post.return_value = response
+
+  transport = TRequestsTransport('http://localhost:12345', session_factory=lambda: session)
+  protocol = TJSONProtocol.TJSONProtocol(transport)
+  client = ReadOnlyScheduler.Client(protocol)
+
+  with pytest.raises(TRequestsTransport.AuthError):
+    client.getRoleSummary()
+
+  transport.close()
 
 
 def test_request_any_other_exception():
@@ -138,9 +153,8 @@ def test_transport_applies_default_user_agent_if_no_factory_provided():
 
 
 def test_auth_type_valid():
-  response = create_autospec(spec=requests.Response, instance=True)
-  response.headers = {'header1': 'data', 'header2': 'data2'}
-  response.raise_for_status.side_effect = requests.exceptions.HTTPError()
+  response = requests.Response()
+  response.status_code = 500
 
   session = create_autospec(spec=requests.Session, instance=True)
   session.headers = {}

http://git-wip-us.apache.org/repos/asf/aurora/blob/9a2bbded/src/test/sh/org/apache/aurora/e2e/test_end_to_end.sh
----------------------------------------------------------------------
diff --git a/src/test/sh/org/apache/aurora/e2e/test_end_to_end.sh b/src/test/sh/org/apache/aurora/e2e/test_end_to_end.sh
index cc7cdee..501d111 100755
--- a/src/test/sh/org/apache/aurora/e2e/test_end_to_end.sh
+++ b/src/test/sh/org/apache/aurora/e2e/test_end_to_end.sh
@@ -271,14 +271,24 @@ test_admin() {
   aurora_admin get_scheduler $_cluster | grep ":8081"
 }
 
-readonly RPC_DATA="[1,\"snapshot\",1,0,{}]"
+restore_netrc() {
+  mv ~/.netrc.bak ~/.netrc >/dev/null 2>&1 || true
+}
+
 test_basic_auth_unauthenticated() {
-  # TODO(ksweeney): Replace this with a call to the client removing the .netrc when AURORA-1248
is
-  # fixed.
-  [[ 401 == $(curl -w '%{http_code}\n' \
-    -o /dev/null \
-    -s 'http://localhost:8081/api' \
-    --data-binary "$RPC_DATA") ]]
+  local _cluster=$1 _role=$2 _env=$3 _job=$4
+  local _config=$5
+  local _jobkey="$_cluster/$_role/$_env/$_job"
+
+  mv ~/.netrc ~/.netrc.bak
+  trap restore_netrc EXIT
+
+  aurora job create $_jobkey $_config || retcode=$?
+  if [[ $retcode != 30 ]]; then
+    echo "Expected auth error exit code, got $retcode"
+    exit 1
+  fi
+  restore_netrc
 }
 
 RETCODE=1
@@ -324,7 +334,7 @@ sudo docker build -t http_example ${TEST_ROOT}
 test_http_example "${TEST_DOCKER_ARGS[@]}"
 
 test_admin "${TEST_ADMIN_ARGS[@]}"
-test_basic_auth_unauthenticated
+test_basic_auth_unauthenticated  "${TEST_ARGS[@]}"
 
 /vagrant/src/test/sh/org/apache/aurora/e2e/test_kerberos_end_to_end.sh
 RETCODE=0


Mime
View raw message