Exemplo n.º 1
0
    def test_start_update_and_wait_success(self):
        mock_config = self.create_mock_config()
        self._fake_context.get_job_config = Mock(return_value=mock_config)
        self._mock_options.wait = True

        resp = self.create_simple_success_response()
        resp.result = Result(startJobUpdateResult=StartJobUpdateResult(
            key=JobUpdateKey(job=JobKey(
                role="role", environment="env", name="name"),
                             id="id")))
        self._mock_api.start_job_update.return_value = resp
        self._mock_api.query_job_updates.side_effect = [
            get_status_query_response(status=JobUpdateStatus.ROLLED_FORWARD)
        ]

        assert self._command.execute(self._fake_context) == EXIT_OK

        assert self._mock_api.start_job_update.mock_calls == [
            call(ANY, None, None)
        ]
        assert self._mock_api.query_job_updates.mock_calls == [
            call(update_key=resp.result.startJobUpdateResult.key)
        ]

        assert self._fake_context.get_out() == [
            StartUpdate.UPDATE_MSG_TEMPLATE %
            ('http://something_or_other/scheduler/role/env/name/update/id'),
            'Current state ROLLED_FORWARD'
        ]
        assert self._fake_context.get_err() == []
Exemplo n.º 2
0
    def test_start_update_command_line_succeeds(self):
        resp = self.create_simple_success_response()
        resp.result = Result(startJobUpdateResult=StartJobUpdateResult(
            key=JobUpdateKey(job=JobKey(
                role="role", environment="env", name="name"),
                             id="id")))
        self._mock_api.start_job_update.return_value = resp
        mock_config = self.create_mock_config()
        self._fake_context.get_job_config = Mock(return_value=mock_config)
        self._mock_options.instance_spec = TaskInstanceKey(self._job_key, None)
        self._mock_options.message = 'hello'

        with patch(
                'apache.aurora.client.cli.update.DiffFormatter') as formatter:
            formatter.return_value = self._formatter
            assert self._command.execute(self._fake_context) == EXIT_OK

        assert self._formatter.show_job_update_diff.mock_calls == [
            call(self._mock_options.instance_spec.instance)
        ]
        assert self._mock_api.start_job_update.mock_calls == [
            call(ANY, 'hello', None, ANY)
        ]
        assert self._fake_context.get_out() == [
            StartUpdate.UPDATE_MSG_TEMPLATE %
            ('http://something_or_other/scheduler/role/env/name/update/id'),
        ]
        assert self._fake_context.get_err() == []
Exemplo n.º 3
0
 def execute(self, context):
   return wait_for_update(
       context,
       self._clock,
       context.get_api(context.options.jobspec.cluster),
       JobUpdateKey(job=context.options.jobspec.to_thrift(), id=context.options.id),
       update_state_to_err_code
   )
Exemplo n.º 4
0
 def test_get_job_update_details(self):
     """Test getting job update details."""
     api, mock_proxy = self.mock_api()
     key = JobUpdateKey(job=JobKey(role="role",
                                   environment="env",
                                   name="name"),
                        id="id")
     api.get_job_update_details(key)
     mock_proxy.getJobUpdateDetails.assert_called_once_with(key)
Exemplo n.º 5
0
 def setUp(self):
     self._command = UpdateWait(clock=mock.create_autospec(spec=time))
     self._mock_options = mock_verb_options(self._command)
     self._mock_options.jobspec = self.TEST_JOBKEY
     self._mock_options.id = 'update_id'
     self._fake_context = FakeAuroraCommandContext()
     self._fake_context.set_options(self._mock_options)
     self._mock_api = self._fake_context.get_api('UNUSED')
     self._fetch_call = call(update_key=JobUpdateKey(
         job=self.TEST_JOBKEY.to_thrift(), id=self._mock_options.id))
Exemplo n.º 6
0
  def test_start_update_and_wait_error(self):
    mock_config = self.create_mock_config()
    self._fake_context.get_job_config = Mock(return_value=mock_config)
    self._mock_options.wait = True

    resp = self.create_simple_success_response()
    resp.result = Result(startJobUpdateResult=StartJobUpdateResult(
        key=JobUpdateKey(job=JobKey(role="role", environment="env", name="name"), id="id")))
    self._mock_api.start_job_update.return_value = resp
    self._mock_api.query_job_updates.side_effect = [
        get_status_query_response(status=JobUpdateStatus.ERROR)
    ]

    with patch('apache.aurora.client.cli.update.DiffFormatter'):
      assert self._command.execute(self._fake_context) == EXIT_UNKNOWN_ERROR
Exemplo n.º 7
0
    def test_start_update_and_wait_rollback(self):
        mock_config = self.create_mock_config()
        self._fake_context.get_job_config = Mock(return_value=mock_config)
        self._mock_options.wait = True

        resp = self.create_simple_success_response()
        resp.result = Result(startJobUpdateResult=StartJobUpdateResult(
            key=JobUpdateKey(job=JobKey(
                role="role", environment="env", name="name"),
                             id="id")))
        self._mock_api.start_job_update.return_value = resp
        self._mock_api.query_job_updates.side_effect = [
            get_status_query_response(status=JobUpdateStatus.ROLLED_BACK)
        ]

        assert self._command.execute(
            self._fake_context) == EXIT_COMMAND_FAILURE
Exemplo n.º 8
0
  def test_start_update_and_open_page(self):
    mock_config = self.create_mock_config()
    self._fake_context.get_job_config = Mock(return_value=mock_config)
    self._mock_options.open_browser = True

    resp = self.create_simple_success_response()
    resp.result = Result(startJobUpdateResult=StartJobUpdateResult(
      key=JobUpdateKey(job=JobKey(role="role", environment="env", name="name"), id="id")))
    self._mock_api.start_job_update.return_value = resp

    with patch('apache.aurora.client.cli.update.DiffFormatter') as formatter:
      formatter.return_value = self._formatter
      assert self._command.execute(self._fake_context) == EXIT_OK

    assert self.mock_webbrowser.mock_calls == [
      call('http://something_or_other/scheduler/role/env/name/update/id')
    ]
Exemplo n.º 9
0
    def test_start_update_command_line_succeeds(self):
        resp = self.create_simple_success_response()
        resp.result = Result(startJobUpdateResult=StartJobUpdateResult(
            key=JobUpdateKey(job=JobKey(
                role="role", environment="env", name="name"),
                             id="id")))
        self._mock_api.start_job_update.return_value = resp
        mock_config = self.create_mock_config()
        self._fake_context.get_job_config = Mock(return_value=mock_config)
        self._mock_options.instance_spec = TaskInstanceKey(self._job_key, None)
        self._mock_options.message = 'hello'
        assert self._command.execute(self._fake_context) == EXIT_OK

        update_url_msg = StartUpdate.UPDATE_MSG_TEMPLATE % (
            'http://something_or_other/scheduler/role/env/name/id')

        assert self._mock_api.start_job_update.mock_calls == [
            call(ANY, 'hello', None)
        ]
        assert self._fake_context.get_out() == [update_url_msg]
        assert self._fake_context.get_err() == []
Exemplo n.º 10
0
class TestJobUpdateApis(unittest.TestCase):
    """Job update APIs tests."""

    UPDATE_CONFIG = {
        'batch_size': 1,
        'watch_secs': 50,
        'max_per_shard_failures': 2,
        'max_total_failures': 1,
        'rollback_on_failure': True,
        'wait_for_batch_completion': False,
    }

    JOB_KEY = AuroraJobKey("foo", "role", "env", "name")
    UPDATE_KEY = JobUpdateKey(job=JOB_KEY.to_thrift(), id="id")

    @classmethod
    def create_blank_response(cls, code, msg):
        return Response(responseCode=code,
                        details=[ResponseDetail(message=msg)],
                        result=create_autospec(spec=Result,
                                               spec_set=True,
                                               instance=True))

    @classmethod
    def create_simple_success_response(cls):
        return cls.create_blank_response(ResponseCode.OK, 'OK')

    @classmethod
    def create_error_response(cls):
        return cls.create_blank_response(ResponseCode.ERROR, 'ERROR')

    @classmethod
    def mock_api(cls):
        api = AuroraClientAPI(Cluster(name="foo"), 'test-client')
        mock_proxy = create_autospec(spec=SchedulerProxyApiSpec,
                                     spec_set=True,
                                     instance=True)
        api._scheduler_proxy = mock_proxy
        return api, mock_proxy

    @classmethod
    def create_update_settings(cls):
        return JobUpdateSettings(
            updateGroupSize=1,
            updateStrategy=JobUpdateStrategy(
                queueStrategy=QueueJobUpdateStrategy(groupSize=1),
                batchStrategy=None,
                varBatchStrategy=None),
            maxPerInstanceFailures=2,
            maxFailedInstances=1,
            minWaitInInstanceRunningMs=50 * 1000,
            rollbackOnFailure=True,
            waitForBatchCompletion=False,
            slaAware=False)

    @classmethod
    def create_update_request(cls, task_config):
        return JobUpdateRequest(instanceCount=5,
                                settings=cls.create_update_settings(),
                                taskConfig=task_config)

    @classmethod
    def mock_job_config(cls, error=None):
        config = create_autospec(spec=AuroraConfig, instance=True)
        update_config = UpdateConfig(batch_size=1,
                                     watch_secs=50,
                                     max_per_shard_failures=2,
                                     max_total_failures=1)
        if error:
            config.update_config.side_effect = error
        else:
            config.update_config.return_value = update_config
        mock_task_config = create_autospec(spec=JobConfiguration,
                                           instance=True)
        mock_task_config.taskConfig = TaskConfig()
        config.job.return_value = mock_task_config
        config.instances.return_value = 5
        return config

    def test_add_instances(self):
        """Test adding instances."""
        api, mock_proxy = self.mock_api()
        job_key = AuroraJobKey("foo", "role", "env", "name")
        mock_proxy.addInstances.return_value = self.create_simple_success_response(
        )
        api.add_instances(job_key, 1, 10)

        mock_proxy.addInstances.assert_called_once_with(
            InstanceKey(jobKey=job_key.to_thrift(), instanceId=1), 10)

    def test_start_job_update(self):
        """Test successful job update start."""
        api, mock_proxy = self.mock_api()
        task_config = TaskConfig()
        mock_proxy.startJobUpdate.return_value = self.create_simple_success_response(
        )

        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', retry=True)

    def test_start_job_update_fails_parse_update_config(self):
        """Test start_job_update fails to parse invalid UpdateConfig."""
        api, mock_proxy = self.mock_api()

        self.assertRaises(AuroraClientAPI.UpdateConfigError,
                          api.start_job_update,
                          self.mock_job_config(error=ValueError()), None)

    def test_get_job_update_diff(self):
        """Test getting job update diff."""
        api, mock_proxy = self.mock_api()
        task_config = TaskConfig()
        mock_proxy.getJobUpdateDiff.return_value = self.create_simple_success_response(
        )

        api.get_job_update_diff(self.mock_job_config(), instances=None)
        mock_proxy.getJobUpdateDiff.assert_called_once_with(
            self.create_update_request(task_config), retry=True)

    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, 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, message='hello')
        mock_proxy.resumeJobUpdate.assert_called_once_with(
            self.UPDATE_KEY, 'hello')

    def test_query_job_updates(self):
        """Test querying job updates."""
        api, mock_proxy = self.mock_api()
        job_key = AuroraJobKey("foo", "role", "env", "name")
        query = JobUpdateQuery(
            jobKey=job_key.to_thrift(),
            updateStatuses={JobUpdateStatus.ROLLING_FORWARD})
        api.query_job_updates(job_key=job_key,
                              update_statuses=query.updateStatuses)
        mock_proxy.getJobUpdateSummaries.assert_called_once_with(query,
                                                                 retry=True)

    def test_query_job_updates_no_filter(self):
        """Test querying job updates with no filter args."""
        api, mock_proxy = self.mock_api()
        query = JobUpdateQuery()
        api.query_job_updates()
        mock_proxy.getJobUpdateSummaries.assert_called_once_with(query,
                                                                 retry=True)

    def test_get_job_update_details(self):
        """Test getting job update details."""
        api, mock_proxy = self.mock_api()
        key = JobUpdateKey(job=JobKey(role="role",
                                      environment="env",
                                      name="name"),
                           id="id")
        api.get_job_update_details(key)
        query = JobUpdateQuery(key=key)
        mock_proxy.getJobUpdateDetails.assert_called_once_with(key,
                                                               query,
                                                               retry=True)

    def test_set_quota(self):
        """Test setting quota."""
        api, mock_proxy = self.mock_api()
        api.set_quota("role", 1.0, 32, 64)
        actual = list(mock_proxy.setQuota.mock_calls[0][1][1].resources)
        assert Resource(numCpus=1.0) in actual
        assert Resource(ramMb=32) in actual
        assert Resource(diskMb=64) in actual
Exemplo n.º 11
0
                                             UpdateInfo, UpdateWait)
from apache.aurora.common.aurora_job_key import AuroraJobKey
from apache.aurora.config import AuroraConfig
from apache.aurora.config.schema.base import Job

from .util import AuroraClientCommandTest, FakeAuroraCommandContext, mock_verb_options

from gen.apache.aurora.api.constants import ACTIVE_JOB_UPDATE_STATES
from gen.apache.aurora.api.ttypes import (
    GetJobUpdateDetailsResult, GetJobUpdateSummariesResult,
    JobInstanceUpdateEvent, JobKey, JobUpdate, JobUpdateAction,
    JobUpdateDetails, JobUpdateEvent, JobUpdateKey, JobUpdateState,
    JobUpdateStatus, JobUpdateSummary, Metadata, Response, ResponseCode,
    ResponseDetail, Result, StartJobUpdateResult)

UPDATE_KEY = JobUpdateKey(job=AuroraClientCommandTest.TEST_JOBKEY.to_thrift(),
                          id="update_id")


def get_status_query_response(count=1, status=JobUpdateStatus.ROLLED_FORWARD):
    return Response(
        responseCode=ResponseCode.OK,
        result=Result(getJobUpdateSummariesResult=GetJobUpdateSummariesResult(
            updateSummaries=[
                JobUpdateSummary(key=UPDATE_KEY,
                                 user="******",
                                 state=JobUpdateState(
                                     status=status,
                                     createdTimestampMs=1411404927,
                                     lastModifiedTimestampMs=14114056030))
                for i in range(count)
            ])))
Exemplo n.º 12
0
  def execute(self, context):
    if context.options.id:
      key = JobUpdateKey(job=context.options.jobspec.to_thrift(), id=context.options.id)
    else:
      key = UpdateController(
          context.get_api(context.options.jobspec.cluster),
          context).get_update_key(context.options.jobspec)
      if key is None:
        context.print_err("There is no active update for this job.")
        return EXIT_INVALID_PARAMETER

    api = context.get_api(context.options.jobspec.cluster)
    response = api.get_job_update_details(key)
    context.log_response_and_raise(response)
    details = response.result.getJobUpdateDetailsResult.details
    if context.options.write_json:
      result = {
        "updateId": ("%s" % details.update.summary.key.id),
        "job": str(context.options.jobspec),
        "started": details.update.summary.state.createdTimestampMs,
        "last_modified": format_timestamp(details.update.summary.state.lastModifiedTimestampMs),
        "status": JobUpdateStatus._VALUES_TO_NAMES[details.update.summary.state.status],
        "update_events": [],
        "instance_update_events": []
      }

      update_events = details.updateEvents
      if update_events is not None and len(update_events) > 0:
        for event in update_events:
          event_data = {
              "status": JobUpdateStatus._VALUES_TO_NAMES[event.status],
              "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:
        for event in instance_events:
          result["instance_update_events"].append({
              "instance": event.instanceId,
              "timestamp": event.timestampMs,
              "action": JobUpdateAction._VALUES_TO_NAMES[event.action]
          })
      context.print_out(json.dumps(result, indent=2, separators=[',', ': '], sort_keys=False))

    else:
      context.print_out("Job: %s, UpdateID: %s" % (context.options.jobspec,
          details.update.summary.key.id))
      context.print_out("Started %s, last activity: %s" %
          (format_timestamp(details.update.summary.state.createdTimestampMs),
          format_timestamp(details.update.summary.state.lastModifiedTimestampMs)))
      context.print_out("Current status: %s" %
          JobUpdateStatus._VALUES_TO_NAMES[details.update.summary.state.status])
      update_events = details.updateEvents
      if update_events is not None and len(update_events) > 0:
        context.print_out("Update events:")
        for event in update_events:
          context.print_out("Status: %s at %s" % (
              JobUpdateStatus._VALUES_TO_NAMES[event.status],
              format_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:")
        for event in instance_events:
          context.print_out("Instance %s at %s: %s" % (
            event.instanceId, format_timestamp(event.timestampMs),
            JobUpdateAction._VALUES_TO_NAMES[event.action]
          ), indent=2)
    return EXIT_OK