It's impossible to figure out the task name from task log only. This
adds a printout that prints the task name after formula is parsed.
Also, if namespace is empty, use the default value, instead of None.
| mkrizek |
| libtaskotron |
It's impossible to figure out the task name from task log only. This
adds a printout that prints the task name after formula is parsed.
Also, if namespace is empty, use the default value, instead of None.
run a task with --debug and see something like this:
[libtaskotron:overlord.py:38] 2017-02-23 16:07:10 DEBUG Found task: dist.rpmlint
also try to modify the formula like this:
namespace:
and see scratch namepsace being correctly used.
| Automatic diff as part of commit; lint not applicable. |
| Automatic diff as part of commit; unit tests not applicable. |
| Path | Packages | |||
|---|---|---|---|---|
| M | libtaskotron/executor.py (6 lines) | |||
| M | libtaskotron/overlord.py (4 lines) | |||
| M | testing/test_executor.py (41 lines) |
| Commit | Tree | Parents | Author | Summary | Date |
|---|---|---|---|---|---|
| 3a5399e5a84b | 8c3aea9c66ef | 0aaf41cb1807 | Kamil Páral | log task name, ignore empty namespace (Show More…) | Feb 23 2017, 4:07 PM |
| Show All 23 Lines | |||||
| 24 | except ImportError, e: | 24 | except ImportError, e: | ||
| 25 | raise exc.TaskotronImportError(e) | 25 | raise exc.TaskotronImportError(e) | ||
| 26 | 26 | | |||
| 27 | 27 | | |||
| 28 | class Executor(object): | 28 | class Executor(object): | ||
| 29 | '''This class serves the purpose of actual task execution. It is instantiated by | 29 | '''This class serves the purpose of actual task execution. It is instantiated by | ||
| 30 | :class:`.Overlord`, :class:`.PersistentMinion` or :class:`.DisposableMinion`. | 30 | :class:`.Overlord`, :class:`.PersistentMinion` or :class:`.DisposableMinion`. | ||
| 31 | 31 | | |||
| 32 | :cvar str default_namespace: namespace to be used when the formula doesn't contain a namespace | ||||
| 33 | definition | ||||
| 32 | :ivar dict formula: parsed task formula | 34 | :ivar dict formula: parsed task formula | ||
| 33 | :ivar dict arg_data: processed cli arguments with some extra runtime variables | 35 | :ivar dict arg_data: processed cli arguments with some extra runtime variables | ||
| 34 | :ivar str workdir: path to working directory; a temporary one is created during execution if | 36 | :ivar str workdir: path to working directory; a temporary one is created during execution if | ||
| 35 | ``None`` | 37 | ``None`` | ||
| 36 | :ivar dict working_data: variables exported from formula directives, to be injected when | 38 | :ivar dict working_data: variables exported from formula directives, to be injected when | ||
| 37 | referenced using ``${variable}`` | 39 | referenced using ``${variable}`` | ||
| 38 | :ivar int exitcode: exit code set by ``exitcode`` directive; it is ``None`` if ``exitcode`` | 40 | :ivar int exitcode: exit code set by ``exitcode`` directive; it is ``None`` if ``exitcode`` | ||
| 39 | directive was not used | 41 | directive was not used | ||
| 40 | ''' | 42 | ''' | ||
| 41 | 43 | | |||
| 44 | default_namespace = 'scratch' | ||||
| 45 | | ||||
| 42 | def __init__(self, formula, arg_data, workdir=None): | 46 | def __init__(self, formula, arg_data, workdir=None): | ||
| 43 | self.formula = formula | 47 | self.formula = formula | ||
| 44 | self.arg_data = arg_data | 48 | self.arg_data = arg_data | ||
| 45 | self.working_data = {} | 49 | self.working_data = {} | ||
| 46 | self.directives = {} | 50 | self.directives = {} | ||
| 47 | self.workdir = workdir | 51 | self.workdir = workdir | ||
| 48 | self.exitcode = None | 52 | self.exitcode = None | ||
| 49 | 53 | | |||
| Show All 26 Lines | 79 | def _run(self): | |||
| 76 | self._validate_input() | 80 | self._validate_input() | ||
| 77 | 81 | | |||
| 78 | if not self.workdir: # create temporary workdir if needed | 82 | if not self.workdir: # create temporary workdir if needed | ||
| 79 | self.workdir = tempfile.mkdtemp(prefix="task-", | 83 | self.workdir = tempfile.mkdtemp(prefix="task-", | ||
| 80 | dir=config.get_config().tmpdir) | 84 | dir=config.get_config().tmpdir) | ||
| 81 | log.debug("Current workdir: %s", self.workdir) | 85 | log.debug("Current workdir: %s", self.workdir) | ||
| 82 | self.arg_data['workdir'] = self.workdir | 86 | self.arg_data['workdir'] = self.workdir | ||
| 83 | self.arg_data['checkname'] = self.formula['name'] | 87 | self.arg_data['checkname'] = self.formula['name'] | ||
| 84 | self.arg_data['namespace'] = self.formula.get('namespace', 'scratch') | 88 | self.arg_data['namespace'] = self.formula.get('namespace') or self.default_namespace | ||
| 85 | 89 | | |||
| 86 | # override variable values | 90 | # override variable values | ||
| 87 | for var, val in self.arg_data['override'].items(): | 91 | for var, val in self.arg_data['override'].items(): | ||
| 88 | log.debug("Overriding variable %s, new value: %s", var, val) | 92 | log.debug("Overriding variable %s, new value: %s", var, val) | ||
| 89 | self.arg_data[var] = eval(val, {}, {}) | 93 | self.arg_data[var] = eval(val, {}, {}) | ||
| 90 | 94 | | |||
| 91 | self._do_actions() | 95 | self._do_actions() | ||
| 92 | 96 | | |||
| ▲ Show 20 Lines • Show All 118 Lines • Show Last 20 Lines | |||||
| Show All 27 Lines | 26 | def __init__(self, arg_data): | |||
|---|---|---|---|---|---|
| 28 | self.exitcode = None | 28 | self.exitcode = None | ||
| 29 | 29 | | |||
| 30 | # parse task formula | 30 | # parse task formula | ||
| 31 | self.formula = config.parse_yaml_from_file(arg_data['task']) | 31 | self.formula = config.parse_yaml_from_file(arg_data['task']) | ||
| 32 | if not self.formula: | 32 | if not self.formula: | ||
| 33 | raise exc.TaskotronYamlError('Task formula file should not be empty: %s' % | 33 | raise exc.TaskotronYamlError('Task formula file should not be empty: %s' % | ||
| 34 | arg_data['task']) | 34 | arg_data['task']) | ||
| 35 | 35 | | |||
| 36 | log.debug('Found task: %s.%s', | ||||
| 37 | self.formula.get('namespace') or executor.Executor.default_namespace, | ||||
| 38 | self.formula['name']) | ||||
| 39 | | ||||
| 36 | def _get_runner(self): | 40 | def _get_runner(self): | ||
| 37 | """Decide the run mode and get appropriate runner (Executor or Minion). | 41 | """Decide the run mode and get appropriate runner (Executor or Minion). | ||
| 38 | 42 | | |||
| 39 | :returns: either :class:`.Executor` (local run mode) or :class:`.PersistentMinion` or | 43 | :returns: either :class:`.Executor` (local run mode) or :class:`.PersistentMinion` or | ||
| 40 | :class:`.DisposableMinion` (remote run mode) | 44 | :class:`.DisposableMinion` (remote run mode) | ||
| 41 | """ | 45 | """ | ||
| 42 | # run locally or remotely | 46 | # run locally or remotely | ||
| 43 | run_remotely = False | 47 | run_remotely = False | ||
| ▲ Show 20 Lines • Show All 53 Lines • Show Last 20 Lines | |||||
| Show First 20 Lines • Show All 357 Lines • ▼ Show 20 Line(s) | 346 | def test_executor_render_multi_variable(self): | |||
|---|---|---|---|---|---|
| 358 | 358 | | |||
| 359 | test_rendered_action = test_executor._render_action(ref_action) | 359 | test_rendered_action = test_executor._render_action(ref_action) | ||
| 360 | 360 | | |||
| 361 | assert (test_rendered_action['dummy']['msg'] == '--foo %s --bar %s' % | 361 | assert (test_rendered_action['dummy']['msg'] == '--foo %s --bar %s' % | ||
| 362 | (ref_var1, ref_var2)) | 362 | (ref_var1, ref_var2)) | ||
| 363 | 363 | | |||
| 364 | 364 | | |||
| 365 | @pytest.mark.usefixtures('setup') | 365 | @pytest.mark.usefixtures('setup') | ||
| 366 | class TestExecutorCheckOverride(): | 366 | class TestExecutorRun(): | ||
| 367 | 367 | | |||
| 368 | @pytest.fixture | 368 | @pytest.fixture | ||
| 369 | def setup(self): | 369 | def setup(self): | ||
| 370 | self.ref_input = {'arch': ['x86_64'], | 370 | self.ref_input = {'arch': ['x86_64'], | ||
| 371 | 'type': 'koji_build', | 371 | 'type': 'koji_build', | ||
| 372 | 'item': 'foo-1.2-3.fc99', | 372 | 'item': 'foo-1.2-3.fc99', | ||
| 373 | 'uuid': '20150220_134110_955656', | 373 | 'uuid': '20150220_134110_955656', | ||
| 374 | 'ssh': None, | 374 | 'ssh': None, | ||
| 375 | 'local': False, | 375 | 'local': False, | ||
| 376 | 'override': ["workdir='/some/dir/'"], | 376 | 'task': 'task.yaml', | ||
| 377 | 'task': 'task.yaml'} | 377 | 'override': []} | ||
| 378 | self.ref_argdata = main.process_args(self.ref_input) | ||||
| 379 | self.ref_formula = {'name': 'rpmlint', | ||||
| 380 | 'namespace': 'dist', | ||||
| 381 | 'desc': 'test task', | ||||
| 382 | 'maintainer': 'Not Sure', | ||||
| 383 | 'actions': []} | ||||
| 378 | 384 | | |||
| 379 | def test_override_existing(self): | 385 | def test_override_existing(self): | ||
| 380 | ref_params = main.process_args(self.ref_input) | 386 | self.ref_input['override'] = ["workdir='/some/dir/'"] | ||
| 387 | self.ref_argdata = main.process_args(self.ref_input) | ||||
| 381 | 388 | | |||
| 382 | test_executor = executor.Executor(Dingus(), ref_params) | 389 | test_executor = executor.Executor(self.ref_formula, self.ref_argdata) | ||
| 383 | test_executor._do_actions = lambda: None | 390 | test_executor._do_actions = lambda: None | ||
| 384 | test_executor._run() | 391 | test_executor._run() | ||
| 385 | 392 | | |||
| 386 | assert test_executor.arg_data['workdir'] == "/some/dir/" | 393 | assert test_executor.arg_data['workdir'] == "/some/dir/" | ||
| 387 | 394 | | |||
| 388 | def test_override_nonexisting(self): | 395 | def test_override_nonexisting(self): | ||
| 389 | self.ref_input['override'] = ["friendship='is magic'"] | 396 | self.ref_input['override'] = ["friendship='is magic'"] | ||
| 390 | ref_params = main.process_args(self.ref_input) | 397 | self.ref_argdata = main.process_args(self.ref_input) | ||
| 391 | 398 | | |||
| 392 | test_executor = executor.Executor(Dingus(), ref_params) | 399 | test_executor = executor.Executor(self.ref_formula, self.ref_argdata) | ||
| 393 | test_executor._do_actions = lambda: None | 400 | test_executor._do_actions = lambda: None | ||
| 394 | test_executor._run() | 401 | test_executor._run() | ||
| 395 | 402 | | |||
| 396 | assert test_executor.arg_data['friendship'] == "is magic" | 403 | assert test_executor.arg_data['friendship'] == "is magic" | ||
| 397 | 404 | | |||
| 405 | def test_no_namespace(self): | ||||
| 406 | '''default namespace should be used for missing namespace''' | ||||
| 407 | self.ref_formula.pop('namespace', None) | ||||
| 408 | | ||||
| 409 | test_executor = executor.Executor(self.ref_formula, self.ref_argdata) | ||||
| 410 | test_executor._do_actions = lambda: None | ||||
| 411 | test_executor._run() | ||||
| 412 | | ||||
| 413 | assert test_executor.arg_data['namespace'] == executor.Executor.default_namespace | ||||
| 414 | | ||||
| 415 | def test_empty_namespace(self): | ||||
| 416 | '''default namespace should be used for empty namespace''' | ||||
| 417 | self.ref_formula['namespace'] = None | ||||
| 418 | | ||||
| 419 | test_executor = executor.Executor(self.ref_formula, self.ref_argdata) | ||||
| 420 | test_executor._do_actions = lambda: None | ||||
| 421 | test_executor._run() | ||||
| 422 | | ||||
| 423 | assert test_executor.arg_data['namespace'] == executor.Executor.default_namespace | ||||
| 424 | | ||||
| 398 | 425 | | |||
| 399 | @pytest.mark.usefixtures('setup') | 426 | @pytest.mark.usefixtures('setup') | ||
| 400 | class TestExecutorPrepareTask(): | 427 | class TestExecutorPrepareTask(): | ||
| 401 | 428 | | |||
| 402 | @pytest.fixture | 429 | @pytest.fixture | ||
| 403 | def setup(self, monkeypatch): | 430 | def setup(self, monkeypatch): | ||
| 404 | self.install_stub = Dingus() | 431 | self.install_stub = Dingus() | ||
| 405 | self.is_installed_stub = Dingus() | 432 | self.is_installed_stub = Dingus() | ||
| Show All 34 Lines | |||||