def test_show_job_update_diff_with_task_diff(self): config = self.get_job_config() self._fake_context.get_job_config = Mock(return_value=config) formatter = DiffFormatter(self._fake_context, config) local_task = self.create_scheduled_tasks()[0].assignedTask.task self._mock_api.get_job_update_diff.return_value = self.get_job_update_diff_result() with contextlib.nested( patch('subprocess.call', return_value=0), patch('json.loads', return_value={})) as (subprocess_patch, _): formatter.show_job_update_diff(self._mock_options.instance_spec.instance, local_task) assert self._mock_api.get_job_update_diff.mock_calls == [ call(config, self._mock_options.instance_spec.instance) ] assert "\n".join(self._fake_context.get_out()) == textwrap.dedent("""\ This job update will: add instances: [10], [12-14] update instances: [11] with diff:\n\n not change instances: [0-9]""") assert subprocess_patch.call_count == 1 assert subprocess_patch.call_args[0][0].startswith( os.environ.get('DIFF_VIEWER', 'diff') + ' ')
def execute(self, context): config = context.get_job_config(context.options.instance_spec.jobkey, context.options.config_file) if context.options.rename_from is not None: cluster = context.options.rename_from.cluster role = context.options.rename_from.role env = context.options.rename_from.environment name = context.options.rename_from.name else: cluster = config.cluster() role = config.role() env = config.environment() name = config.name() api = context.get_api(cluster) resp = api.populate_job_config(config) context.log_response_and_raise(resp, err_code=EXIT_INVALID_CONFIGURATION, err_msg="Error loading configuration") local_task = resp.result.populateJobResult.taskConfig # Deepcopy is important here as tasks will be modified for printing. local_tasks = [deepcopy(local_task) for _ in range(config.instances())] instances = ( None if context.options.instance_spec.instance == ALL_INSTANCES else context.options.instance_spec.instance ) formatter = DiffFormatter(context, config, cluster, role, env, name) if config.raw().has_cron_schedule(): formatter.diff_no_update_details(local_tasks) else: formatter.show_job_update_diff(instances, local_task) return EXIT_OK
def test_show_job_update_diff_with_task_diff(self): config = self.get_job_config() self._fake_context.get_job_config = Mock(return_value=config) formatter = DiffFormatter(self._fake_context, config) local_task = self.create_scheduled_tasks()[0].assignedTask.task local_task.constraints = set([Constraint(name='host'), Constraint(name='rack')]) self._mock_api.get_job_update_diff.return_value = self.get_job_update_diff_result() formatter.show_job_update_diff(self._mock_options.instance_spec.instance, local_task) assert self._mock_api.get_job_update_diff.mock_calls == [ call(config, self._mock_options.instance_spec.instance) ] assert "\n".join(self._fake_context.get_out()) == textwrap.dedent("""\ This job update will: add instances: [10], [12-14] update instances: [11] with diff:\n 2c2,3 < 'constraints': None, --- > 'constraints': [ Constraint(name='host', constraint=None), > Constraint(name='rack', constraint=None)], \n not change instances: [0-9]""")
def test_show_job_update_diff_with_task_diff(self): config = self.get_job_config() self._fake_context.get_job_config = Mock(return_value=config) formatter = DiffFormatter(self._fake_context, config) local_task = self.create_scheduled_tasks()[0].assignedTask.task self._mock_api.get_job_update_diff.return_value = self.get_job_update_diff_result( ) with contextlib.nested(patch('subprocess.call', return_value=0), patch('json.loads', return_value={})) as (subprocess_patch, _): formatter.show_job_update_diff( self._mock_options.instance_spec.instance, local_task) assert self._mock_api.get_job_update_diff.mock_calls == [ call(config, self._mock_options.instance_spec.instance) ] assert "\n".join( self._fake_context.get_out()) == textwrap.dedent("""\ This job update will: add instances: [10], [12-14] update instances: [11] with diff:\n\n not change instances: [0-9]""") assert subprocess_patch.call_count == 1 assert subprocess_patch.call_args[0][0].startswith( os.environ.get('DIFF_VIEWER', 'diff') + ' ')
def execute(self, context): job = context.options.instance_spec.jobkey instances = (None if context.options.instance_spec.instance == ALL_INSTANCES else context.options.instance_spec.instance) config = context.get_job_config(job, context.options.config_file) if config.raw().has_cron_schedule(): raise context.CommandError( EXIT_COMMAND_FAILURE, "Cron jobs may only be updated with \"aurora cron schedule\" command") api = context.get_api(config.cluster()) formatter = DiffFormatter(context, config) formatter.show_job_update_diff(instances) try: resp = api.start_job_update(config, context.options.message, instances) except AuroraClientAPI.UpdateConfigError as e: raise context.CommandError(EXIT_INVALID_CONFIGURATION, e.message) context.log_response_and_raise(resp, err_code=EXIT_API_ERROR, err_msg="Failed to start update due to error:") if resp.result: update_key = resp.result.startJobUpdateResult.key url = get_update_page( api, AuroraJobKey.from_thrift(config.cluster(), update_key.job), resp.result.startJobUpdateResult.key.id) context.print_out(self.UPDATE_MSG_TEMPLATE % url) if context.options.wait: return wait_for_update(context, self._clock, api, update_key) else: context.print_out(combine_messages(resp)) return EXIT_OK
def test_diff_no_update_details_success(self): config = self.get_job_config(is_cron=True) self._fake_context.get_job_config = Mock(return_value=config) formatter = DiffFormatter(self._fake_context, config) self._mock_api.query.return_value = self.create_empty_task_result() query = TaskQuery( jobKeys=[self.TEST_JOBKEY.to_thrift()], statuses=ACTIVE_STATES) self._mock_api.build_query.return_value = query local_tasks = [] formatter.diff_no_update_details(local_tasks)
def test_get_job_update_diff_error(self): mock_config = self.get_job_config() self._fake_context.get_job_config = Mock(return_value=mock_config) formatter = DiffFormatter(self._fake_context, mock_config) self._mock_api.get_job_update_diff.return_value = self.create_error_response() with pytest.raises(Context.CommandError): formatter.show_job_update_diff(self._mock_options.instance_spec.instance) assert self._mock_api.get_job_update_diff.mock_calls == [ call(mock_config, self._mock_options.instance_spec.instance) ] assert self._fake_context.get_out() == [] assert self._fake_context.get_err() == ["Error getting diff info from scheduler", "\tWhoops"]
def test_show_job_update_diff_no_change(self): config = self.get_job_config() self._fake_context.get_job_config = Mock(return_value=config) formatter = DiffFormatter(self._fake_context, config) self._mock_api.get_job_update_diff.return_value = self.get_job_update_no_change_diff_result() formatter.show_job_update_diff(self._mock_options.instance_spec.instance) assert self._mock_api.get_job_update_diff.mock_calls == [ call(config, self._mock_options.instance_spec.instance) ] assert "\n".join(self._fake_context.get_out()) == textwrap.dedent("""\ This job update will: not change instances: [0-3]""")
def execute(self, context): job = context.options.instance_spec.jobkey instances = (None if context.options.instance_spec.instance == ALL_INSTANCES else context.options.instance_spec.instance) update_id = str(uuid.uuid4()) config = context.get_job_config(job, context.options.config_file) if config.raw().has_cron_schedule(): raise context.CommandError( EXIT_COMMAND_FAILURE, "Cron jobs may only be updated with \"aurora cron schedule\" command" ) api = context.get_api(config.cluster()) formatter = DiffFormatter(context, config) formatter.show_job_update_diff(instances) try: resp = api.start_job_update(config, context.options.message, instances, {CLIENT_UPDATE_ID: update_id}) except AuroraClientAPI.UpdateConfigError as e: raise context.CommandError(EXIT_INVALID_CONFIGURATION, e.message) if not self._is_update_already_in_progress(resp, update_id): context.log_response_and_raise( resp, err_code=EXIT_API_ERROR, err_msg=self.FAILED_TO_START_UPDATE_ERROR_MSG) if resp.result: update_key = resp.result.startJobUpdateResult.key url = get_update_page( api, AuroraJobKey.from_thrift(config.cluster(), update_key.job), resp.result.startJobUpdateResult.key.id) context.print_out(self.UPDATE_MSG_TEMPLATE % url) if context.options.open_browser: webbrowser.open_new_tab(url) if context.options.wait: return wait_for_update(context, self._clock, api, update_key, update_state_to_err_code) else: context.print_out(combine_messages(resp)) return EXIT_OK
def execute(self, context): job = context.options.instance_spec.jobkey instances = (None if context.options.instance_spec.instance == ALL_INSTANCES else context.options.instance_spec.instance) update_id = str(uuid.uuid4()) config = context.get_job_config(job, context.options.config_file) if config.raw().has_cron_schedule(): raise context.CommandError( EXIT_COMMAND_FAILURE, "Cron jobs may only be updated with \"aurora cron schedule\" command") api = context.get_api(config.cluster()) formatter = DiffFormatter(context, config) formatter.show_job_update_diff(instances) try: resp = api.start_job_update(config, context.options.message, instances, {CLIENT_UPDATE_ID: update_id}) except AuroraClientAPI.UpdateConfigError as e: raise context.CommandError(EXIT_INVALID_CONFIGURATION, e.message) if not self._is_update_already_in_progress(resp, update_id): context.log_response_and_raise(resp, err_code=EXIT_API_ERROR, err_msg=self.FAILED_TO_START_UPDATE_ERROR_MSG) if resp.result: update_key = resp.result.startJobUpdateResult.key url = get_update_page( api, AuroraJobKey.from_thrift(config.cluster(), update_key.job), resp.result.startJobUpdateResult.key.id) context.print_out(self.UPDATE_MSG_TEMPLATE % url) if context.options.open_browser: webbrowser.open_new_tab(url) if context.options.wait: return wait_for_update(context, self._clock, api, update_key, update_state_to_err_code) else: context.print_out(combine_messages(resp)) return EXIT_OK
def test_diff_no_update_details_success(self): config = self.get_job_config(is_cron=True) self._fake_context.get_job_config = Mock(return_value=config) formatter = DiffFormatter(self._fake_context, config) self._mock_api.query.return_value = self.create_empty_task_result() query = TaskQuery( jobKeys=[self.TEST_JOBKEY.to_thrift()], statuses=ACTIVE_STATES) self._mock_api.build_query.return_value = query local_tasks = [] with contextlib.nested( patch('subprocess.call', return_value=0), patch('json.loads', return_value={})) as (subprocess_patch, _): formatter.diff_no_update_details(local_tasks) assert subprocess_patch.call_count == 1 assert subprocess_patch.call_args[0][0].startswith( os.environ.get('DIFF_VIEWER', 'diff') + ' ')
def test_diff_no_update_details_success(self): config = self.get_job_config(is_cron=True) self._fake_context.get_job_config = Mock(return_value=config) formatter = DiffFormatter(self._fake_context, config) self._mock_api.query.return_value = self.create_empty_task_result() query = TaskQuery(jobKeys=[self.TEST_JOBKEY.to_thrift()], statuses=ACTIVE_STATES) self._mock_api.build_query.return_value = query local_tasks = [] with contextlib.nested(patch('subprocess.call', return_value=0), patch('json.loads', return_value={})) as (subprocess_patch, _): formatter.diff_no_update_details(local_tasks) assert subprocess_patch.call_count == 1 assert subprocess_patch.call_args[0][0].startswith( os.environ.get('DIFF_VIEWER', 'diff') + ' ')
def execute(self, context): config = context.get_job_config(context.options.instance_spec.jobkey, context.options.config_file) if context.options.rename_from is not None: cluster = context.options.rename_from.cluster role = context.options.rename_from.role env = context.options.rename_from.environment name = context.options.rename_from.name else: cluster = config.cluster() role = config.role() env = config.environment() name = config.name() api = context.get_api(cluster) resp = api.populate_job_config(config) context.log_response_and_raise(resp, err_code=EXIT_INVALID_CONFIGURATION, err_msg="Error loading configuration") local_task = resp.result.populateJobResult.taskConfig # Deepcopy is important here as tasks will be modified for printing. local_tasks = [deepcopy(local_task) for _ in range(config.instances())] instances = (None if context.options.instance_spec.instance == ALL_INSTANCES else context.options.instance_spec.instance) formatter = DiffFormatter(context, config, cluster, role, env, name) if config.raw().has_cron_schedule(): formatter.diff_no_update_details(local_tasks) else: formatter.show_job_update_diff(instances, local_task) return EXIT_OK
def execute(self, context): job = context.options.instance_spec.jobkey instances = (None if context.options.instance_spec.instance == ALL_INSTANCES else context.options.instance_spec.instance) config = context.get_job_config(job, context.options.config_file) if config.raw().has_cron_schedule(): raise context.CommandError( EXIT_COMMAND_FAILURE, "Cron jobs may only be updated with \"aurora cron schedule\" command" ) api = context.get_api(config.cluster()) formatter = DiffFormatter(context, config) formatter.show_job_update_diff(instances) try: resp = api.start_job_update(config, context.options.message, instances) except AuroraClientAPI.UpdateConfigError as e: raise context.CommandError(EXIT_INVALID_CONFIGURATION, e.message) context.log_response_and_raise( resp, err_code=EXIT_API_ERROR, err_msg="Failed to start update due to error:") if resp.result: update_key = resp.result.startJobUpdateResult.key url = get_update_page( api, AuroraJobKey.from_thrift(config.cluster(), update_key.job), resp.result.startJobUpdateResult.key.id) context.print_out(self.UPDATE_MSG_TEMPLATE % url) if context.options.wait: return wait_for_update(context, self._clock, api, update_key) else: context.print_out(combine_messages(resp)) return EXIT_OK