aurora-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mchucarr...@apache.org
Subject git commit: Bridge framework for client v2. (See AURORA-76)
Date Fri, 07 Feb 2014 19:55:59 GMT
Updated Branches:
  refs/heads/master 4dcddab2f -> e6f415085


Bridge framework for client v2. (See AURORA-76)

Reviewed in 17270.


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

Branch: refs/heads/master
Commit: e6f415085d6fb066687e91fb3025c18f27df0ae4
Parents: 4dcddab
Author: Mark Chu-Carroll <mchucarroll@twopensource.com>
Authored: Fri Feb 7 14:36:17 2014 -0500
Committer: Mark Chu-Carroll <mchucarroll@twitter.com>
Committed: Fri Feb 7 14:36:17 2014 -0500

----------------------------------------------------------------------
 src/main/python/apache/aurora/client/bin/BUILD  |  9 ++-
 src/main/python/apache/aurora/client/cli/BUILD  | 25 +++++--
 .../python/apache/aurora/client/cli/__init__.py | 50 ++++++--------
 .../python/apache/aurora/client/cli/bridge.py   | 52 ++++++++++++++
 .../python/apache/aurora/client/cli/client.py   | 51 ++++++++++++++
 src/test/python/apache/aurora/client/cli/BUILD  | 12 +++-
 .../apache/aurora/client/cli/test_bridge.py     | 73 ++++++++++++++++++++
 .../aurora/client/cli/test_cancel_update.py     |  2 +-
 .../apache/aurora/client/cli/test_create.py     |  2 +-
 .../apache/aurora/client/cli/test_diff.py       |  2 +-
 .../apache/aurora/client/cli/test_kill.py       |  4 +-
 .../apache/aurora/client/cli/test_quota.py      |  2 +-
 .../apache/aurora/client/cli/test_restart.py    |  3 +-
 .../apache/aurora/client/cli/test_status.py     |  2 +-
 .../apache/aurora/client/cli/test_update.py     |  3 +-
 15 files changed, 250 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/main/python/apache/aurora/client/bin/BUILD
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/bin/BUILD b/src/main/python/apache/aurora/client/bin/BUILD
index 19fd9d3..dbabfd0 100644
--- a/src/main/python/apache/aurora/client/bin/BUILD
+++ b/src/main/python/apache/aurora/client/bin/BUILD
@@ -16,9 +16,16 @@
 
 python_binary(
   name = 'aurora_client',
-  source = 'aurora_client.py',
   entry_point = 'apache.aurora.client.bin.aurora_client:proxy_main',
   dependencies = [
+    pants(':aurora_client_lib')
+  ]
+)
+
+python_library(
+  name = 'aurora_client_lib',
+  sources = [ 'aurora_client.py' ],
+  dependencies = [
     pants('3rdparty/python:twitter.common.app'),
     pants('3rdparty/python:twitter.common.log'),
     pants('src/main/python/apache/aurora/client/commands:all'),

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/main/python/apache/aurora/client/cli/BUILD
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/BUILD b/src/main/python/apache/aurora/client/cli/BUILD
index 63954d6..f5c9ae7 100644
--- a/src/main/python/apache/aurora/client/cli/BUILD
+++ b/src/main/python/apache/aurora/client/cli/BUILD
@@ -16,13 +16,30 @@
 
 python_binary(
   name='client',
-  entry_point = 'apache.aurora.client.cli:main',
-  dependencies = [ pants(':cli') ],
-  )
+  entry_point = 'apache.aurora.client.cli.client:proxy_main',
+  dependencies = [
+    pants(':client_lib')
+  ],
+)
+
+python_library(
+  name = 'bridge',
+  sources = ['bridge.py']
+)
+
+python_library(
+  name = 'client_lib',
+  sources = [ 'client.py' ],
+  dependencies = [
+    pants(':cli'),
+    pants(':bridge'),
+    pants('src/main/python/apache/aurora/client/bin:aurora_client_lib')
+  ]
+)
 
 python_library(
   name='cli',
-  sources = globs('*.py'),
+  sources = [ '__init__.py', 'jobs.py', 'quota.py', 'context.py', 'options.py' ],
   dependencies = [
     pants('3rdparty/python:argparse'),
     pants('3rdparty/python:twitter.common.python'),

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/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 14a6676..9eb5c52 100644
--- a/src/main/python/apache/aurora/client/cli/__init__.py
+++ b/src/main/python/apache/aurora/client/cli/__init__.py
@@ -112,11 +112,13 @@ class CommandLine(object):
   """The top-level object implementing a command-line application."""
 
   def __init__(self):
-    self.nouns = {}
+    self.nouns = None
     self.parser = None
 
   def register_noun(self, noun):
     """Add a noun to the application"""
+    if self.nouns is None:
+      self.nouns = {}
     if not isinstance(noun, Noun):
       raise TypeError('register_noun requires a Noun argument')
     self.nouns[noun.name] = noun
@@ -132,18 +134,34 @@ class CommandLine(object):
   def register_nouns(self):
     """This method should overridden by applications to register the collection of nouns
     that they can manipulate.
+
+    Noun registration is done on-demand, when either get_nouns or execute is called.
+    This allows the command-line tool a small amount of self-customizability depending
+    on the environment in which it is being used.
+
+    For example, if a cluster is being run via AWS, then you could provide an
+    AWS noun with a set of operations for querying AWS status, billing stats,
+    etc. You wouldn't want to clutter the help output with AWS commands for users
+    that weren't using AWS. So you could have the command-line check the cluster.json
+    file, and only register the AWS noun if there was an AWS cluster.
+
     """
-    pass
+
+  @property
+  def registered_nouns(self):
+    if self.nouns is None:
+      self.register_nouns()
+    return self.nouns.keys()
 
   def execute(self, args):
     """Execute a command.
     :param args: the command-line arguments for the command. This only includes arguments
         that should be parsed by the application; it does not include sys.argv[0].
     """
-    self.register_nouns()
+    nouns = self.registered_nouns
     self.setup_options_parser()
     options = self.parser.parse_args(args)
-    if options.noun not in self.nouns:
+    if options.noun not in nouns:
       raise ValueError('Unknown command: %s' % options.noun)
     noun = self.nouns[options.noun]
     context = noun.create_context()
@@ -210,27 +228,3 @@ class Verb(AuroraCommand):
   def execute(self, context):
     pass
 
-
-class AuroraCommandLine(CommandLine):
-  """ An example implementation of a command line application using this framework.
-  This should probably eventually get moved in to its own source file.
-  """
-
-  @classmethod
-  def get_description(cls):
-    return 'Aurora client command line'
-
-  def register_nouns(self):
-    from .jobs import Job
-    self.register_noun(Job())
-    from .quota import Quota
-    self.register_noun(Quota())
-
-
-def main():
-  cmd = AuroraCommandLine()
-  cmd.execute(sys.argv[1:])
-
-
-if __name__ == '__main__':
-  main(sys.argv)

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/main/python/apache/aurora/client/cli/bridge.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/bridge.py b/src/main/python/apache/aurora/client/cli/bridge.py
new file mode 100644
index 0000000..27079da
--- /dev/null
+++ b/src/main/python/apache/aurora/client/cli/bridge.py
@@ -0,0 +1,52 @@
+import sys
+
+
+class CommandProcessor(object):
+  """A wrapper for anything which can receive a set of command-line parameters and execute
+  something using them.
+
+  This is built assuming that the first command-line parameter is the name of
+  a command to be executed. For example, if this was being used to build a command-line
+  tool named "tool", then a typical invocation from the command-line would look like
+  "tool cmd arg1 arg2". "cmd" would be the name of the command to execute, and
+  "arg1" and "arg2" would be the parameters to that command.
+  """
+
+  def execute(self, args):
+    """Execute the command-line tool wrapped by this processor.
+
+    :param args: a list of the parameters used to invoke the command. Typically,
+        this will be sys.argv.
+    """
+    pass
+
+  def get_commands(self):
+    """Get a list of the commands that this processor can handle."""
+    pass
+
+
+class Bridge(object):
+  """Given multiple command line programs, each represented by a "CommandProcessor" object,
+  refer command invocations to the command line that knows how to process them.
+  """
+
+  def __init__(self, command_processors, default=None):
+    """
+    :param command_processors: a list of command-processors.
+    :param default: the default command processor. any command which is not
+      reported by "get_commands" as part of any of the registered processors
+      will be passed to the default.
+    """
+    self.command_processors = command_processors
+    self.default = default
+
+  def execute(self, args):
+    """Dispatch a command line to the appropriate CommandProcessor"""
+    for cl in self.command_processors:
+      if args[1] in cl.get_commands():
+        return cl.execute(args)
+    if self.default is not None:
+      return self.default.execute(args)
+    else:
+      print('Unknown command: %s' % args[1])
+      sys.exit(1)

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/main/python/apache/aurora/client/cli/client.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/cli/client.py b/src/main/python/apache/aurora/client/cli/client.py
new file mode 100644
index 0000000..e416d38
--- /dev/null
+++ b/src/main/python/apache/aurora/client/cli/client.py
@@ -0,0 +1,51 @@
+import sys
+
+from apache.aurora.client.cli import CommandLine
+from apache.aurora.client.cli.bridge import Bridge, CommandProcessor
+
+
+class AuroraCommandLine(CommandLine):
+  """The CommandLine implementation for the Aurora client v2 command line."""
+
+  @classmethod
+  def get_description(cls):
+    return 'Aurora client command line'
+
+  def register_nouns(self):
+    super(AuroraCommandLine, self).register_nouns()
+    from apache.aurora.client.cli.jobs import Job
+    self.register_noun(Job())
+    from apache.aurora.client.cli.quota import Quota
+    self.register_noun(Quota())
+
+
+class AuroraClientV2CommandProcessor(CommandProcessor):
+  def __init__(self):
+    self.commandline = AuroraCommandLine()
+
+  def get_commands(self):
+    return self.commandline.registered_nouns
+
+  def execute(self, args):
+    return self.commandline.execute(args[1:])
+
+
+class AuroraClientV1CommandProcessor(CommandProcessor):
+  # TODO(mchucarroll): deprecate client v1. (AURORA-131)
+  def get_commands(self):
+    return ["cancel_update", "create", "diff", "get_quota", "inspect", "kill", "list_jobs",
+        "open", "restart", "run", "ssh", "start_cron", "status", "update", "version" ]
+
+  def execute(self, args):
+    from apache.aurora.client.bin.aurora_client import proxy_main as clientone_proxy_main
+    return clientone_proxy_main()
+
+
+def proxy_main():
+  v2 = AuroraClientV2CommandProcessor()
+  v1 = AuroraClientV1CommandProcessor()
+  bridge = Bridge([v2, v1], default=v1)
+  bridge.execute(sys.argv)
+
+if __name__ == '__main__':
+  proxy_main()

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/BUILD
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/BUILD b/src/test/python/apache/aurora/client/cli/BUILD
index 51cc380..c106b97 100644
--- a/src/test/python/apache/aurora/client/cli/BUILD
+++ b/src/test/python/apache/aurora/client/cli/BUILD
@@ -16,7 +16,7 @@
 
 python_test_suite(
   name = 'all',
-  dependencies = [ pants(':job'), pants(':quota') ]
+  dependencies = [ pants(':bridge'), pants(':job'), pants(':quota') ]
 )
 
 python_library(
@@ -29,6 +29,14 @@ python_library(
 )
 
 python_tests(
+  name = 'bridge',
+  sources = [ 'test_bridge.py' ],
+  dependencies = [
+    pants('src/main/python/apache/aurora/client/cli:bridge'),
+  ]
+)
+
+python_tests(
   name = 'job',
   sources = [
     'test_cancel_update.py',
@@ -44,6 +52,7 @@ python_tests(
     pants('3rdparty/python:mock'),
     pants('3rdparty/python:twitter.common.contextutil'),
     pants('src/main/python/apache/aurora/client/cli'),
+    pants('src/main/python/apache/aurora/client/cli:client'),
     pants('src/test/python/apache/aurora/client/commands:util')
   ]
 )
@@ -56,6 +65,7 @@ python_tests(
     pants('3rdparty/python:mock'),
     pants('3rdparty/python:twitter.common.contextutil'),
     pants('src/main/python/apache/aurora/client/cli'),
+    pants('src/main/python/apache/aurora/client/cli:client'),
     pants('src/test/python/apache/aurora/client/commands:util')
   ]
 )

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_bridge.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_bridge.py b/src/test/python/apache/aurora/client/cli/test_bridge.py
new file mode 100644
index 0000000..d944981
--- /dev/null
+++ b/src/test/python/apache/aurora/client/cli/test_bridge.py
@@ -0,0 +1,73 @@
+import unittest
+
+from apache.aurora.client.cli.bridge import Bridge, CommandProcessor
+
+
+class CommandOne(CommandProcessor):
+  def get_commands(self):
+    return ['one', 'two', 'three']
+
+  def execute(self, args):
+    return 1
+
+
+class CommandTwo(CommandProcessor):
+  def get_commands(self):
+    return ['three', 'four', 'five']
+
+  def execute(self, args):
+    return 2
+
+
+class CommandThree(CommandProcessor):
+  def get_commands(self):
+    return ['six']
+
+  def execute(self, args):
+    return '3[%s]' % args[1]
+
+
+class TestBridgedCommandLine(unittest.TestCase):
+  def setUp(self):
+    self.one = CommandOne()
+    self.two = CommandTwo()
+    self.three = CommandThree()
+
+  def test_bridge_with_default_three(self):
+    bridge = Bridge([self.one, self.two, self.three], default=self.three)
+    assert bridge.execute(['test', 'one']) == 1
+    assert bridge.execute(['test', 'two']) == 1
+    assert bridge.execute(['test', 'three']) == 1
+    assert bridge.execute(['test', 'four']) == 2
+    assert bridge.execute(['test', 'five']) == 2
+    assert bridge.execute(['test', 'six']) == '3[six]'
+    assert bridge.execute(['test', 'seven']) == '3[seven]'
+    assert bridge.execute(['test', 'eight']) == '3[eight]'
+
+  def test_bridge_with_default_one(self):
+    bridge = Bridge([self.one, self.two, self.three], default=self.one)
+    assert bridge.execute(['test', 'one']) == 1
+    assert bridge.execute(['test', 'two']) == 1
+    assert bridge.execute(['test', 'three']) == 1
+    assert bridge.execute(['test', 'four']) == 2
+    assert bridge.execute(['test', 'five']) == 2
+    assert bridge.execute(['test', 'six']) == '3[six]'
+    assert bridge.execute(['test', 'seven']) == 1
+    assert bridge.execute(['test', 'eight']) == 1
+
+  def test_bridge_with_no_default(self):
+    bridge = Bridge([self.one, self.two, self.three])
+    assert bridge.execute(['test', 'one']) == 1
+    assert bridge.execute(['test', 'two']) == 1
+    assert bridge.execute(['test', 'three']) == 1
+    assert bridge.execute(['test', 'four']) == 2
+    assert bridge.execute(['test', 'five']) == 2
+    assert bridge.execute(['test', 'six']) == '3[six]'
+    self.assertRaises(SystemExit, bridge.execute, ['test', 'seven'])
+
+  def test_bridge_ordering(self):
+    bridge1 = Bridge([self.one, self.two, self.three])
+    bridge2 = Bridge([self.two, self.one, self.three])
+    assert bridge1.execute(['test', 'three']) == 1
+    assert bridge2.execute(['test', 'three']) == 2
+

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_cancel_update.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_cancel_update.py b/src/test/python/apache/aurora/client/cli/test_cancel_update.py
index 92de1b9..e5cd7e5 100644
--- a/src/test/python/apache/aurora/client/cli/test_cancel_update.py
+++ b/src/test/python/apache/aurora/client/cli/test_cancel_update.py
@@ -16,7 +16,7 @@
 
 import contextlib
 
-from apache.aurora.client.cli import AuroraCommandLine
+from apache.aurora.client.cli.client import AuroraCommandLine
 from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext
 from apache.aurora.common.aurora_job_key import AuroraJobKey
 from twitter.common.contextutil import temporary_file

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/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 330bde5..4fff616 100644
--- a/src/test/python/apache/aurora/client/cli/test_create.py
+++ b/src/test/python/apache/aurora/client/cli/test_create.py
@@ -29,10 +29,10 @@ from gen.apache.aurora.ttypes import (
 )
 
 from apache.aurora.client.cli import (
-    AuroraCommandLine,
     EXIT_COMMAND_FAILURE,
     EXIT_INVALID_CONFIGURATION
 )
+from apache.aurora.client.cli.client import AuroraCommandLine
 from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext
 from apache.aurora.client.hooks.hooked_api import HookedAuroraClientAPI
 from apache.aurora.config import AuroraConfig

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_diff.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_diff.py b/src/test/python/apache/aurora/client/cli/test_diff.py
index 32433c1..9c23a60 100644
--- a/src/test/python/apache/aurora/client/cli/test_diff.py
+++ b/src/test/python/apache/aurora/client/cli/test_diff.py
@@ -17,10 +17,10 @@
 import contextlib
 
 from apache.aurora.client.cli import (
-    AuroraCommandLine,
     EXIT_INVALID_CONFIGURATION,
     EXIT_INVALID_PARAMETER
 )
+from apache.aurora.client.cli.client import AuroraCommandLine
 from apache.aurora.client.cli.util import AuroraClientCommandTest
 
 from gen.apache.aurora.constants import ACTIVE_STATES

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/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 9c593b9..6040ed4 100644
--- a/src/test/python/apache/aurora/client/cli/test_kill.py
+++ b/src/test/python/apache/aurora/client/cli/test_kill.py
@@ -17,7 +17,9 @@
 import contextlib
 import unittest
 
-from apache.aurora.client.cli import AuroraCommandLine
+from twitter.common.contextutil import temporary_file
+
+from apache.aurora.client.cli.client import AuroraCommandLine
 from apache.aurora.client.hooks.hooked_api import HookedAuroraClientAPI
 from apache.aurora.common.aurora_job_key import AuroraJobKey
 from twitter.common.contextutil import temporary_file

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/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 d582fce..f7d3585 100644
--- a/src/test/python/apache/aurora/client/cli/test_quota.py
+++ b/src/test/python/apache/aurora/client/cli/test_quota.py
@@ -16,7 +16,7 @@
 
 import contextlib
 
-from apache.aurora.client.cli import AuroraCommandLine
+from apache.aurora.client.cli.client import AuroraCommandLine
 from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext
 
 from gen.apache.aurora.ttypes import (

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/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 3c04433..aa23d5b 100644
--- a/src/test/python/apache/aurora/client/cli/test_restart.py
+++ b/src/test/python/apache/aurora/client/cli/test_restart.py
@@ -2,7 +2,8 @@ import contextlib
 import functools
 
 from apache.aurora.client.api.health_check import InstanceWatcherHealthCheck, Retriable
-from apache.aurora.client.cli import AuroraCommandLine, EXIT_API_ERROR
+from apache.aurora.client.cli import EXIT_API_ERROR
+from apache.aurora.client.cli.client import AuroraCommandLine
 from apache.aurora.client.cli.util import AuroraClientCommandTest
 
 from twitter.common.contextutil import temporary_file

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_status.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/cli/test_status.py b/src/test/python/apache/aurora/client/cli/test_status.py
index 38e14b1..c543f3d 100644
--- a/src/test/python/apache/aurora/client/cli/test_status.py
+++ b/src/test/python/apache/aurora/client/cli/test_status.py
@@ -29,9 +29,9 @@ from gen.apache.aurora.ttypes import (
 )
 
 from apache.aurora.client.cli import (
-    AuroraCommandLine,
     EXIT_INVALID_PARAMETER
 )
+from apache.aurora.client.cli.client import AuroraCommandLine
 from apache.aurora.common.aurora_job_key import AuroraJobKey
 from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext
 

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/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 c469da4..51858b9 100644
--- a/src/test/python/apache/aurora/client/cli/test_update.py
+++ b/src/test/python/apache/aurora/client/cli/test_update.py
@@ -6,7 +6,8 @@ from twitter.common.contextutil import temporary_file
 from apache.aurora.client.api.updater import Updater
 from apache.aurora.client.api.health_check import InstanceWatcherHealthCheck, Retriable
 from apache.aurora.client.api.quota_check import QuotaCheck
-from apache.aurora.client.cli import AuroraCommandLine, EXIT_INVALID_CONFIGURATION
+from apache.aurora.client.cli import EXIT_INVALID_CONFIGURATION
+from apache.aurora.client.cli.client import AuroraCommandLine
 from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext
 from apache.aurora.config import AuroraConfig
 


Mime
View raw message