aurora-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wfar...@apache.org
Subject incubator-aurora git commit: Add client support for including messages when changing update state.
Date Fri, 13 Mar 2015 02:36:54 GMT
Repository: incubator-aurora
Updated Branches:
  refs/heads/master ee1a13afb -> 76c76ca7c


Add client support for including messages when changing update state.

More plumbing.

Bugs closed: AURORA-1077

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


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

Branch: refs/heads/master
Commit: 76c76ca7cd2a2070cb3b7f9b8d8c94ea537e0964
Parents: ee1a13a
Author: Bill Farner <wfarner@apache.org>
Authored: Thu Mar 12 19:35:40 2015 -0700
Committer: Bill Farner <wfarner@apache.org>
Committed: Thu Mar 12 19:35:40 2015 -0700

----------------------------------------------------------------------
 .../python/apache/aurora/client/api/__init__.py | 20 +++---
 .../python/apache/aurora/client/cli/update.py   | 67 +++++++++++++-------
 .../apache/aurora/client/hooks/hooked_api.py    |  4 +-
 src/test/python/apache/aurora/api_util.py       |  8 +--
 .../python/apache/aurora/client/api/test_api.py | 17 +++--
 .../apache/aurora/client/cli/test_supdate.py    | 39 +++++++-----
 6 files changed, 95 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/76c76ca7/src/main/python/apache/aurora/client/api/__init__.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/api/__init__.py b/src/main/python/apache/aurora/client/api/__init__.py
index 4025781..a81329f 100644
--- a/src/main/python/apache/aurora/client/api/__init__.py
+++ b/src/main/python/apache/aurora/client/api/__init__.py
@@ -149,11 +149,12 @@ class AuroraClientAPI(object):
 
     return updater.update(instances)
 
-  def start_job_update(self, config, instances=None):
+  def start_job_update(self, config, message, instances=None):
     """Requests Scheduler to start job update process.
 
     Arguments:
     config -- AuroraConfig instance with update details.
+    message -- Audit message to include with the change.
     instances -- Optional list of instances to restrict update to.
 
     Returns response object with update ID and acquired job lock.
@@ -170,37 +171,40 @@ class AuroraClientAPI(object):
         taskConfig=config.job().taskConfig
     )
 
-    return self._scheduler_proxy.startJobUpdate(request)
+    return self._scheduler_proxy.startJobUpdate(request, message)
 
-  def pause_job_update(self, update_key):
+  def pause_job_update(self, update_key, message):
     """Requests Scheduler to pause active job update.
 
     Arguments:
     update_key -- Update identifier.
+    message -- Audit message to include with the change.
 
     Returns response object.
     """
-    return self._scheduler_proxy.pauseJobUpdate(update_key)
+    return self._scheduler_proxy.pauseJobUpdate(update_key, message)
 
-  def resume_job_update(self, update_key):
+  def resume_job_update(self, update_key, message):
     """Requests Scheduler to resume a job update paused previously.
 
     Arguments:
     update_key -- Update identifier.
+    message -- Audit message to include with the change.
 
     Returns response object.
     """
-    return self._scheduler_proxy.resumeJobUpdate(update_key)
+    return self._scheduler_proxy.resumeJobUpdate(update_key, message)
 
-  def abort_job_update(self, update_key):
+  def abort_job_update(self, update_key, message):
     """Requests Scheduler to abort active or paused job update.
 
     Arguments:
     update_key -- Update identifier.
+    message -- Audit message to include with the change.
 
     Returns response object.
     """
-    return self._scheduler_proxy.abortJobUpdate(update_key)
+    return self._scheduler_proxy.abortJobUpdate(update_key, message)
 
   def query_job_updates(self, role=None, job_key=None, user=None, update_statuses=None):
     """Returns all job updates matching the query.

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/76c76ca7/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 37cc498..cced108 100644
--- a/src/main/python/apache/aurora/client/cli/update.py
+++ b/src/main/python/apache/aurora/client/cli/update.py
@@ -78,28 +78,36 @@ class UpdateController(object):
     self.context.print_out(success_msg)
     return EXIT_OK
 
-  def pause(self, job_key):
+  def pause(self, job_key, message):
     return self._modify_update(
         job_key,
-        lambda key: self.api.pause_job_update(key),
+        lambda key: self.api.pause_job_update(key, message),
         "Failed to pause update due to error:",
         "Update has been paused.")
 
-  def resume(self, job_key):
+  def resume(self, job_key, message):
     return self._modify_update(
         job_key,
-        lambda key: self.api.resume_job_update(key),
+        lambda key: self.api.resume_job_update(key, message),
         "Failed to resume update due to error:",
         "Update has been resumed.")
 
-  def abort(self, job_key):
+  def abort(self, job_key, message):
     return self._modify_update(
         job_key,
-        lambda key: self.api.abort_job_update(key),
+        lambda key: self.api.abort_job_update(key, message),
         "Failed to abort update due to error:",
         "Update has been aborted.")
 
 
+MESSAGE_OPTION = CommandOption(
+    '--message',
+    '-m',
+    type=str,
+    default=None,
+    help='Message to include with the update state transition')
+
+
 class StartUpdate(Verb):
 
   UPDATE_MSG_TEMPLATE = "Job update has started. View your update progress at %s"
@@ -110,8 +118,14 @@ class StartUpdate(Verb):
 
   def get_options(self):
     return [
-      BIND_OPTION, BROWSER_OPTION, JSON_READ_OPTION, HEALTHCHECK_OPTION, STRICT_OPTION,
-      INSTANCES_SPEC_ARGUMENT, CONFIG_ARGUMENT
+        BIND_OPTION,
+        BROWSER_OPTION,
+        HEALTHCHECK_OPTION,
+        JSON_READ_OPTION,
+        MESSAGE_OPTION,
+        STRICT_OPTION,
+        INSTANCES_SPEC_ARGUMENT,
+        CONFIG_ARGUMENT
     ]
 
   @property
@@ -127,7 +141,6 @@ class StartUpdate(Verb):
         You may want to consider using the 'aurora job diff' subcommand before updating,
         to preview what changes will take effect.
         """)
-  # TODO(mchucarroll): consider adding an "aurora update preview"?
 
   def execute(self, context):
     job = context.options.instance_spec.jobkey
@@ -140,7 +153,7 @@ class StartUpdate(Verb):
           "Cron jobs may only be updated with \"aurora cron schedule\" command")
 
     api = context.get_api(config.cluster())
-    resp = api.start_job_update(config, instances)
+    resp = api.start_job_update(config, context.options.message, instances)
     context.log_response_and_raise(resp, err_code=EXIT_API_ERROR,
         err_msg="Failed to start update due to error:")
 
@@ -158,9 +171,7 @@ class PauseUpdate(Verb):
     return 'pause'
 
   def get_options(self):
-    return [
-      JOBSPEC_ARGUMENT
-    ]
+    return [JOBSPEC_ARGUMENT, MESSAGE_OPTION]
 
   @property
   def help(self):
@@ -168,7 +179,9 @@ class PauseUpdate(Verb):
 
   def execute(self, context):
     job_key = context.options.jobspec
-    return UpdateController(context.get_api(job_key.cluster), context).pause(job_key)
+    return UpdateController(context.get_api(job_key.cluster), context).pause(
+        job_key,
+        context.options.message)
 
 
 class ResumeUpdate(Verb):
@@ -177,9 +190,7 @@ class ResumeUpdate(Verb):
     return 'resume'
 
   def get_options(self):
-    return [
-      JOBSPEC_ARGUMENT
-    ]
+    return [JOBSPEC_ARGUMENT, MESSAGE_OPTION]
 
   @property
   def help(self):
@@ -187,7 +198,9 @@ class ResumeUpdate(Verb):
 
   def execute(self, context):
     job_key = context.options.jobspec
-    return UpdateController(context.get_api(job_key.cluster), context).resume(job_key)
+    return UpdateController(context.get_api(job_key.cluster), context).resume(
+        job_key,
+        context.options.message)
 
 
 class AbortUpdate(Verb):
@@ -196,9 +209,7 @@ class AbortUpdate(Verb):
     return 'abort'
 
   def get_options(self):
-    return [
-      JOBSPEC_ARGUMENT
-    ]
+    return [JOBSPEC_ARGUMENT, MESSAGE_OPTION]
 
   @property
   def help(self):
@@ -206,7 +217,9 @@ class AbortUpdate(Verb):
 
   def execute(self, context):
     job_key = context.options.jobspec
-    return UpdateController(context.get_api(job_key.cluster), context).abort(job_key)
+    return UpdateController(context.get_api(job_key.cluster), context).abort(
+        job_key,
+        context.options.message)
 
 
 class ListUpdates(Verb):
@@ -307,9 +320,13 @@ class UpdateStatus(Verb):
       update_events = details.updateEvents
       if update_events is not None and len(update_events) > 0:
         for event in update_events:
-          result["update_events"].append({
+          event_data = {
               "status": JobUpdateStatus._VALUES_TO_NAMES[event.status],
-              "timestampMs": event.timestampMs})
+              "timestampMs": event.timestampMs
+          }
+          if event.message:
+            event_data["message"] = event.message
+          result["update_events"].append(event_data)
 
       instance_events = details.instanceEvents
       if instance_events is not None and len(instance_events) > 0:
@@ -340,6 +357,8 @@ class UpdateStatus(Verb):
               JobUpdateStatus._VALUES_TO_NAMES[event.status],
               timestamp(event.timestampMs)
           ), indent=2)
+          if event.message:
+            context.print_out("  message: %s" % event.message, indent=4)
       instance_events = details.instanceEvents
       if instance_events is not None and len(instance_events) > 0:
         context.print_out("Instance events:")

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/76c76ca7/src/main/python/apache/aurora/client/hooks/hooked_api.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/client/hooks/hooked_api.py b/src/main/python/apache/aurora/client/hooks/hooked_api.py
index 60a5aad..7fc0b71 100644
--- a/src/main/python/apache/aurora/client/hooks/hooked_api.py
+++ b/src/main/python/apache/aurora/client/hooks/hooked_api.py
@@ -184,7 +184,7 @@ class HookedAuroraClientAPI(NonHookedAuroraClientAPI):
             config, health_check_interval_seconds=health_check_interval_seconds,
             instances=instances))
 
-  def start_job_update(self, config, instances=None):
+  def start_job_update(self, config, message, instances=None):
     return self._hooked_call(config, None,
         _partial(super(HookedAuroraClientAPI, self).start_job_update,
-            config, instances=instances))
+            config, message, instances=instances))

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/76c76ca7/src/test/python/apache/aurora/api_util.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/api_util.py b/src/test/python/apache/aurora/api_util.py
index 7059955..5b2a538 100644
--- a/src/test/python/apache/aurora/api_util.py
+++ b/src/test/python/apache/aurora/api_util.py
@@ -100,16 +100,16 @@ class SchedulerThriftApiSpec(ReadOnlyScheduler.Iface):
   def replaceCronTemplate(self, config, lock):
     pass
 
-  def startJobUpdate(self, request):
+  def startJobUpdate(self, request, message):
     pass
 
-  def pauseJobUpdate(self, jobKey):
+  def pauseJobUpdate(self, jobKey, message):
     pass
 
-  def resumeJobUpdate(self, jobKey):
+  def resumeJobUpdate(self, jobKey, message):
     pass
 
-  def abortJobUpdate(self, jobKey):
+  def abortJobUpdate(self, jobKey, message):
     pass
 
   def pulseJobUpdate(self, updateId):

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/76c76ca7/src/test/python/apache/aurora/client/api/test_api.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/client/api/test_api.py b/src/test/python/apache/aurora/client/api/test_api.py
index d211fb9..b56e352 100644
--- a/src/test/python/apache/aurora/client/api/test_api.py
+++ b/src/test/python/apache/aurora/client/api/test_api.py
@@ -120,8 +120,10 @@ class TestJobUpdateApis(unittest.TestCase):
     task_config = TaskConfig()
     mock_proxy.startJobUpdate.return_value = self.create_simple_success_response()
 
-    api.start_job_update(self.mock_job_config())
-    mock_proxy.startJobUpdate.assert_called_once_with(self.create_update_request(task_config))
+    api.start_job_update(self.mock_job_config(), instances=None, message='hello')
+    mock_proxy.startJobUpdate.assert_called_once_with(
+        self.create_update_request(task_config),
+        'hello')
 
   def test_start_job_update_fails_parse_update_config(self):
     """Test start_job_update fails to parse invalid UpdateConfig."""
@@ -130,23 +132,24 @@ class TestJobUpdateApis(unittest.TestCase):
     self.assertRaises(
         AuroraClientAPI.UpdateConfigError,
         api.start_job_update,
-        self.mock_job_config(error=ValueError()))
+        self.mock_job_config(error=ValueError()),
+        None)
 
   def test_pause_job_update(self):
     """Test successful job update pause."""
     api, mock_proxy = self.mock_api()
     mock_proxy.pauseJobUpdate.return_value = self.create_simple_success_response()
 
-    api.pause_job_update(self.UPDATE_KEY)
-    mock_proxy.pauseJobUpdate.assert_called_once_with(self.UPDATE_KEY)
+    api.pause_job_update(self.UPDATE_KEY, message='hello')
+    mock_proxy.pauseJobUpdate.assert_called_once_with(self.UPDATE_KEY, 'hello')
 
   def test_resume_job_update(self):
     """Test successful job update resume."""
     api, mock_proxy = self.mock_api()
     mock_proxy.resumeJobUpdate.return_value = self.create_simple_success_response()
 
-    api.resume_job_update(self.UPDATE_KEY)
-    mock_proxy.resumeJobUpdate.assert_called_once_with(self.UPDATE_KEY)
+    api.resume_job_update(self.UPDATE_KEY, message='hello')
+    mock_proxy.resumeJobUpdate.assert_called_once_with(self.UPDATE_KEY, 'hello')
 
   def test_query_job_updates(self):
     """Test querying job updates."""

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/76c76ca7/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 370a46b..a237da9 100644
--- a/src/test/python/apache/aurora/client/cli/test_supdate.py
+++ b/src/test/python/apache/aurora/client/cli/test_supdate.py
@@ -88,7 +88,7 @@ class TestStartUpdateCommand(AuroraClientCommandTest):
       self._command.execute(self._fake_context)
 
     assert self._mock_api.start_job_update.mock_calls == [
-        call(mock_config, self._mock_options.instance_spec.instance)
+        call(mock_config, None, self._mock_options.instance_spec.instance)
     ]
 
     self.assert_lock_message(self._fake_context)
@@ -111,7 +111,7 @@ class TestStartUpdateCommand(AuroraClientCommandTest):
     self._command.execute(self._fake_context)
 
     assert self._mock_api.start_job_update.mock_calls == [
-        call(mock_config, self._mock_options.instance_spec.instance)
+        call(mock_config, None, self._mock_options.instance_spec.instance)
     ]
 
 
@@ -160,7 +160,12 @@ class TestUpdateCommand(AuroraClientCommandTest):
         fp.write(self.get_valid_config())
         fp.flush()
         cmd = AuroraCommandLine()
-        result = cmd.execute(['beta-update', 'start', self.TEST_JOBSPEC, fp.name])
+        result = cmd.execute([
+            'beta-update',
+            'start',
+            self.TEST_JOBSPEC,
+            fp.name,
+            '--message=hello'])
         assert result == EXIT_OK
 
       update_url_msg = StartUpdate.UPDATE_MSG_TEMPLATE % (
@@ -169,7 +174,8 @@ class TestUpdateCommand(AuroraClientCommandTest):
       assert mock_api.start_job_update.call_count == 1
       args, kwargs = mock_api.start_job_update.call_args
       assert isinstance(args[0], AuroraConfig)
-      assert args[1] is None
+      assert args[1] == 'hello'
+      assert args[2] is None
       assert mock_context.get_out() == [update_url_msg]
       assert mock_context.get_err() == []
 
@@ -208,12 +214,12 @@ class TestUpdateCommand(AuroraClientCommandTest):
         fp.write(self.get_valid_config())
         fp.flush()
         cmd = AuroraCommandLine()
-        result = cmd.execute(['beta-update', 'pause', self.TEST_JOBSPEC])
+        result = cmd.execute(['beta-update', 'pause', self.TEST_JOBSPEC, '-m=hello'])
         assert result == EXIT_OK
 
       assert mock_api.query_job_updates.mock_calls == [
         call(update_statuses=ACTIVE_JOB_UPDATE_STATES, job_key=self.TEST_JOBKEY)]
-      assert mock_api.pause_job_update.mock_calls == [call(UPDATE_KEY)]
+      assert mock_api.pause_job_update.mock_calls == [call(UPDATE_KEY, 'hello')]
       assert mock_context.get_out() == ["Update has been paused."]
       assert mock_context.get_err() == []
 
@@ -229,12 +235,12 @@ class TestUpdateCommand(AuroraClientCommandTest):
         fp.write(self.get_valid_config())
         fp.flush()
         cmd = AuroraCommandLine()
-        result = cmd.execute(['beta-update', 'abort', self.TEST_JOBSPEC])
+        result = cmd.execute(['beta-update', 'abort', self.TEST_JOBSPEC, '-m=hello'])
         assert result == EXIT_OK
 
       assert mock_api.query_job_updates.mock_calls == [
         call(update_statuses=ACTIVE_JOB_UPDATE_STATES, job_key=self.TEST_JOBKEY)]
-      assert mock_api.abort_job_update.mock_calls == [call(UPDATE_KEY)]
+      assert mock_api.abort_job_update.mock_calls == [call(UPDATE_KEY, 'hello')]
       assert mock_context.get_out() == ["Update has been aborted."]
       assert mock_context.get_err() == []
 
@@ -250,12 +256,12 @@ class TestUpdateCommand(AuroraClientCommandTest):
         fp.write(self.get_valid_config())
         fp.flush()
         cmd = AuroraCommandLine()
-        result = cmd.execute(['beta-update', 'resume', self.TEST_JOBSPEC])
+        result = cmd.execute(['beta-update', 'resume', self.TEST_JOBSPEC, '--message=hello'])
         assert result == EXIT_OK
 
       assert mock_api.query_job_updates.mock_calls == [
         call(update_statuses=ACTIVE_JOB_UPDATE_STATES, job_key=self.TEST_JOBKEY)]
-      assert mock_api.resume_job_update.mock_calls == [call(UPDATE_KEY)]
+      assert mock_api.resume_job_update.mock_calls == [call(UPDATE_KEY, 'hello')]
       assert mock_context.get_out() == ["Update has been resumed."]
 
   def test_update_invalid_config(self):
@@ -289,7 +295,7 @@ class TestUpdateCommand(AuroraClientCommandTest):
 
       assert mock_api.query_job_updates.mock_calls == [
         call(update_statuses=ACTIVE_JOB_UPDATE_STATES, job_key=self.TEST_JOBKEY)]
-      assert mock_api.resume_job_update.mock_calls == [call(UPDATE_KEY)]
+      assert mock_api.resume_job_update.mock_calls == [call(UPDATE_KEY, None)]
       assert mock_context.get_out() == []
       assert mock_context.get_err() == ["Failed to resume update due to error:", "\tWhoops"]
 
@@ -310,7 +316,7 @@ class TestUpdateCommand(AuroraClientCommandTest):
 
       assert mock_api.query_job_updates.mock_calls == [
         call(update_statuses=ACTIVE_JOB_UPDATE_STATES, job_key=self.TEST_JOBKEY)]
-      assert mock_api.abort_job_update.mock_calls == [call(UPDATE_KEY)]
+      assert mock_api.abort_job_update.mock_calls == [call(UPDATE_KEY, None)]
       assert mock_context.get_out() == []
       assert mock_context.get_err() == ["Failed to abort update due to error:", "\tWhoops"]
 
@@ -355,7 +361,7 @@ class TestUpdateCommand(AuroraClientCommandTest):
 
       assert mock_api.query_job_updates.mock_calls == [
         call(update_statuses=ACTIVE_JOB_UPDATE_STATES, job_key=self.TEST_JOBKEY)]
-      assert mock_api.pause_job_update.mock_calls == [call(UPDATE_KEY)]
+      assert mock_api.pause_job_update.mock_calls == [call(UPDATE_KEY, None)]
       assert mock_context.get_out() == []
       assert mock_context.get_err() == ["Failed to pause update due to error:", "\tWhoops"]
 
@@ -453,6 +459,7 @@ class TestUpdateCommand(AuroraClientCommandTest):
                 timestampMs=3000),
             JobUpdateEvent(
                 status=JobUpdateStatus.ROLL_FORWARD_PAUSED,
+                message="Investigating issues",
                 timestampMs=4000),
             JobUpdateEvent(
                 status=JobUpdateStatus.ROLLING_FORWARD,
@@ -496,6 +503,7 @@ Current status: ROLLING_FORWARD
 Update events:
   Status: ROLLING_FORWARD at %(ctime)s
   Status: ROLL_FORWARD_PAUSED at %(ctime)s
+      message: Investigating issues
   Status: ROLLING_FORWARD at %(ctime)s
 Instance events:
   Instance 1 at %(ctime)s: INSTANCE_UPDATING
@@ -532,11 +540,12 @@ Instance events:
           "started": 1000,
           "update_events": [
               {
-                "status": "ROLLING_FORWARD",
-                "timestampMs": 3000
+                  "status": "ROLLING_FORWARD",
+                  "timestampMs": 3000
               },
               {
                   "status": "ROLL_FORWARD_PAUSED",
+                  "message": "Investigating issues",
                   "timestampMs": 4000
               },
               {


Mime
View raw message