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 |