uber-compose 2.1.5b1__tar.gz → 2.1.5b3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/PKG-INFO +1 -1
  2. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/__init__.py +2 -0
  3. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/docker_compose.py +28 -5
  4. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/docker_compose_shell/interface.py +30 -20
  5. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/docker_compose_shell/types.py +8 -0
  6. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/health_policy.py +2 -0
  7. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/uber_compose.py +15 -3
  8. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/vedro_plugin/base_structures/common_json_cli.py +8 -0
  9. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose.egg-info/PKG-INFO +1 -1
  10. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/LICENSE +0 -0
  11. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/README.md +0 -0
  12. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/setup.cfg +0 -0
  13. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/setup.py +0 -0
  14. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/__init__.py +0 -0
  15. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/constants.py +0 -0
  16. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/docker_compose_shell/__init__.py +0 -0
  17. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/sequence_run_types.py +0 -0
  18. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/system_docker_compose.py +0 -0
  19. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/utils/__init__.py +0 -0
  20. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/utils/compose_files.py +0 -0
  21. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/utils/compose_instance_cfg.py +0 -0
  22. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/utils/env_files.py +0 -0
  23. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/utils/process_command_output.py +0 -0
  24. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/utils/shell_process.py +0 -0
  25. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/core/utils/state_waiting.py +0 -0
  26. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/env_description/__init__.py +0 -0
  27. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/env_description/env_tools.py +0 -0
  28. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/env_description/env_types.py +0 -0
  29. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/errors/__init__.py +0 -0
  30. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/errors/migrations.py +0 -0
  31. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/errors/up.py +0 -0
  32. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/__init__.py +0 -0
  33. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/broken_services.py +0 -0
  34. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/bytes_pickle.py +0 -0
  35. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/countdown_counter.py +0 -0
  36. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/exec_record.py +0 -0
  37. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/exec_result.py +0 -0
  38. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/jobs_result.py +0 -0
  39. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/labels.py +0 -0
  40. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/singleton.py +0 -0
  41. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/helpers/state_keeper.py +0 -0
  42. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/output/__init__.py +0 -0
  43. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/output/console.py +0 -0
  44. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/output/styles.py +0 -0
  45. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/utils/__init__.py +0 -0
  46. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/utils/docker_compose_files_path.py +0 -0
  47. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/utils/docker_compose_service_deps.py +0 -0
  48. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/utils/search_docker_compose_files.py +0 -0
  49. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/utils/services_construction.py +0 -0
  50. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/vedro_plugin/__init__.py +0 -0
  51. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/vedro_plugin/base_structures/__init__.py +0 -0
  52. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/vedro_plugin/helpers/__init__.py +0 -0
  53. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/vedro_plugin/helpers/scenario_ordering.py +0 -0
  54. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/vedro_plugin/helpers/scenario_tag_processing.py +0 -0
  55. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/vedro_plugin/helpers/test_env_vars_setter.py +0 -0
  56. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/vedro_plugin/plugin.py +0 -0
  57. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/version +0 -0
  58. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose/version.py +0 -0
  59. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose.egg-info/SOURCES.txt +0 -0
  60. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose.egg-info/dependency_links.txt +0 -0
  61. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose.egg-info/requires.txt +0 -0
  62. {uber_compose-2.1.5b1 → uber_compose-2.1.5b3}/uber_compose.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uber-compose
3
- Version: 2.1.5b1
3
+ Version: 2.1.5b3
4
4
  Summary: docker compose testing env orchestrator
5
5
  Home-page: https://github.com/ko10ok/uber-compose
6
6
  Author: Yuriy Sagitov
@@ -1,3 +1,4 @@
1
+ from uber_compose.core.docker_compose_shell.types import ExecLifeCyclePolicy
1
2
  from uber_compose.core.docker_compose_shell.interface import ProcessExit
2
3
  from uber_compose.core.docker_compose_shell.interface import TimeOutCheck
3
4
  from uber_compose.core.sequence_run_types import ComposeConfig
@@ -24,6 +25,7 @@ __all__ = (
24
25
  'TheUberCompose', 'SystemUberCompose',
25
26
  'Environment', 'Service', 'Env', 'OverridenService',
26
27
  'CommonJsonCli', 'CommandResult', 'ProcessExit', 'JsonParser', 'json_parser', 'ExecTimeout', 'TimeOutCheck',
28
+ 'ExecLifeCyclePolicy',
27
29
  'VedroUberCompose', 'UpHealthPolicy', 'DEFAULT_COMPOSE', 'ComposeConfig', 'DEFAULT_ENV_DESCRIPTION',
28
30
  'DEFAULT_ENV_ID',
29
31
  )
@@ -112,24 +112,47 @@ class ComposeInstance:
112
112
  # TODO check if need to template migrations
113
113
  # substituted_cmd = handler.cmd.format(**env_config_instance.env_services_map)
114
114
  substituted_cmd = handler.cmd
115
- migrate_result = await self.compose_executor.dc_exec_until_state(
115
+ migration_result = await self.compose_executor.dc_exec_until_state(
116
116
  target_service, substituted_cmd,
117
117
  kill_before=False,
118
118
  kill_after=False,
119
119
  )
120
- if not migrate_result.check_result:
120
+
121
+ migration_errors = [error for error in migration_result.stderr.split(b'\n') if error] # empty or none skips
122
+ skipper_migration_errors = [
123
+ current_error
124
+ for current_error in migration_errors
125
+ if any(
126
+ skip_error in current_error for skip_error in (self.health_policy.skip_migrations_errors or [])
127
+ )
128
+ ]
129
+
130
+ for skipped_error in skipper_migration_errors:
131
+ self.logger.stage_info(
132
+ Text(
133
+ f'⚠️Skipping migration error for "{substituted_cmd}" on {target_service}:'
134
+ f'\n{skipped_error=}'
135
+ )
136
+ )
137
+
138
+ critical_migration_errors = [
139
+ error
140
+ for error in migration_errors
141
+ if error not in skipper_migration_errors
142
+ ]
143
+ if not migration_result.finished or critical_migration_errors:
121
144
  services_status = await self.compose_executor.dc_state()
122
145
  error = Text(f"Can't migrate service {target_service}, with {substituted_cmd}", style=Style.bad).append(
123
- Text(f"\n{migrate_result.stdout=}\n",style=Style.regular)
146
+ Text(f"\n{migration_result.stdout=}\n",style=Style.regular)
124
147
  ).append(
125
- Text(f"{migrate_result.stderr=}", style=Style.bad)
148
+ Text(f"{migration_result.stderr=}", style=Style.bad)
126
149
  ).append(
127
150
  services_status.as_rich_text()
128
151
  )
129
152
  self.logger.error(error)
130
153
  self.logger.error_details(f"\nServices logs:\n {await self.logs(services)}")
131
154
  raise ServicesUpError(f"Can't migrate service {target_service}, with {substituted_cmd}"
132
- f"\n{migrate_result.stdout=}\n{migrate_result.stderr=}"
155
+ f"\n{migration_result.stdout=}\n{migration_result.stderr=}"
133
156
  f"\nServices status:\n {services_status.as_rich_text()}") from None
134
157
 
135
158
  async def run_services_pack(self, services: list[str], migrations):
@@ -315,10 +315,9 @@ class ComposeShellInterface:
315
315
  self.logger.stage_debug(stderr.decode('utf-8'))
316
316
 
317
317
  class ExecResult(NamedTuple):
318
- check_result: bool
319
- err: OperationError | None = None
320
318
  stdout: str = ''
321
319
  stderr: str = ''
320
+ finished: bool = False
322
321
 
323
322
  async def dc_exec_until_state(self, container: str,
324
323
  cmd: str,
@@ -343,7 +342,7 @@ class ComposeShellInterface:
343
342
  if kill_before:
344
343
  await self.dc_exec(container, f'killall {cmd_name}')
345
344
 
346
- check_done_result = True
345
+ check_finished_result = True
347
346
  if cmd.endswith('&'):
348
347
  self.logger.stage_details(f'Command {cmd} is detached-mode running, skipping any finish checks')
349
348
  cmd = cmd[:-1]
@@ -353,39 +352,50 @@ class ComposeShellInterface:
353
352
  detached=(wait != ProcessExit()))
354
353
 
355
354
  if isinstance(result, OperationError):
356
- check_done_result = False
355
+ self.logger.stage_details(Text(f'Running command "{cmd}" leads to error:\n {result}', style=Style.info))
356
+ check_finished_result = False
357
357
 
358
358
  if wait == ProcessExit():
359
- self.logger.stage_info(Text('Retrieving process IDs wait completion', style=Style.info))
359
+ self.logger.stage_info(Text('Retrieving in-container process IDs and wait completion', style=Style.info))
360
360
  process_ids = await retry(
361
361
  attempts=timeout.attempts,
362
362
  delay=timeout.delay_s,
363
363
  until=lambda pids: pids != [] and pids != [-1]
364
364
  )(self._dc_exec_process_pids)(container, cmd)
365
365
  self.logger.stage_debug(f'pids retrieved {process_ids}')
366
- if process_ids:
367
- if process_ids == [-1]:
368
- self.logger.stage_details(
369
- f'Process:\n{cmd}\nwas not checked for completion due to no "pidof" tool in container'
366
+ if process_ids == [-1]:
367
+ self.logger.stage_details(Text(
368
+ (
369
+ f'Process:\n{cmd}\nwas not checked for completion '
370
+ f'due to no "pidof" tool in container {container}'
371
+ ),
372
+ style=Style.suspicious
373
+ ))
374
+ check_finished_result = False
375
+ elif process_ids:
376
+ self.logger.error(Text('Process was not completed', style=Style.suspicious))
377
+ check_finished_result = False
378
+ if break_on_timeout:
379
+ raise ExecWasntSuccesfullyDone(
380
+ f'\nProcess\n{cmd}\nwas not finished in {timeout.attempts}x'
381
+ f'{timeout.delay_s} seconds'
370
382
  )
371
- else:
372
- self.logger.error(Text('Process was not completed', style=Style.suspicious))
373
- check_done_result = False
374
- if break_on_timeout:
375
- raise ExecWasntSuccesfullyDone(
376
- f'\nProcess\n{cmd}\nwas not finished in {timeout.attempts}x'
377
- f'{timeout.delay_s} seconds'
378
- )
383
+ else:
384
+ check_finished_result = True
379
385
  elif isinstance(wait, Callable):
380
386
  if asyncio.iscoroutinefunction(wait):
381
- check_done_result = await wait(container, cmd, env, extra_env, break_on_timeout)
387
+ check_finished_result = await wait(container, cmd, env, extra_env, break_on_timeout)
382
388
  else:
383
- check_done_result = wait(container, cmd, env, extra_env, break_on_timeout)
389
+ check_finished_result = wait(container, cmd, env, extra_env, break_on_timeout)
384
390
 
385
391
  if kill_after:
386
392
  await self.dc_exec(container, f'killall {cmd_name}')
387
393
 
388
- return ComposeShellInterface.ExecResult(check_done_result, err=result, stdout=stdout, stderr=stderr)
394
+ return ComposeShellInterface.ExecResult(
395
+ stdout=stdout,
396
+ stderr=stderr,
397
+ finished=check_finished_result,
398
+ )
389
399
 
390
400
  @retry(attempts=3, delay=1, until=lambda x: x == JobResult.BAD)
391
401
  async def dc_down(self, services: list[str], env: dict = None,
@@ -8,6 +8,14 @@ from rich.text import Text
8
8
  from uber_compose.output.styles import Style
9
9
 
10
10
 
11
+ @dataclass
12
+ class ExecLifeCyclePolicy:
13
+ """Policy for skipping phases of command execution life cycle to reduce time consumption."""
14
+ kill_before_same_old_command_running: bool = True
15
+ kill_after_command_still_running: bool = True
16
+ break_on_timeout: bool = True
17
+
18
+
11
19
  class ComposeState:
12
20
  RUNNING = 'running'
13
21
  EXITED = 'exited'
@@ -9,3 +9,5 @@ class UpHealthPolicy:
9
9
  service_up_check_delay_s: int = 3
10
10
 
11
11
  pre_check_delay_s: float = 0
12
+
13
+ skip_migrations_errors: list[bytes] = None
@@ -1,10 +1,12 @@
1
1
  import shlex
2
2
  from dataclasses import dataclass
3
+ from typing import Any
3
4
  from typing import Callable
4
5
  from uuid import uuid4
5
6
 
6
7
  from rich.text import Text
7
8
 
9
+ from uber_compose.core.docker_compose_shell.types import ExecLifeCyclePolicy
8
10
  from uber_compose.core.docker_compose_shell.interface import TimeOutCheck
9
11
  from uber_compose.core.docker_compose_shell.types import ServicesComposeState
10
12
 
@@ -174,9 +176,10 @@ class SystemUberCompose:
174
176
  container: str,
175
177
  command: str,
176
178
  extra_env: dict[str, str] = None,
177
- wait: Callable | ProcessExit | None = ProcessExit(),
179
+ wait: Callable[..., bool] | ProcessExit | None = ProcessExit(),
178
180
  env_id: str = DEFAULT_ENV_ID,
179
181
  timeout: TimeOutCheck = None,
182
+ life_cycle_policy: ExecLifeCyclePolicy = ExecLifeCyclePolicy()
180
183
  ) -> ExecResult | ExecTimeout:
181
184
  uid = str(uuid4())
182
185
  log_file = f'{uid}.log'
@@ -196,13 +199,22 @@ class SystemUberCompose:
196
199
  container = service_state.get_any().labels[Label.SERVICE_NAME]
197
200
 
198
201
  cmd = f'sh -c \'{shlex.quote(command)[1:-1]} > /tmp/{log_file} 2>&1\''
199
- res = await dc_shell.dc_exec_until_state(container, cmd, extra_env=extra_env, wait=wait, timeout=timeout)
202
+ res = await dc_shell.dc_exec_until_state(
203
+ container=container,
204
+ cmd=cmd,
205
+ extra_env=extra_env,
206
+ wait=wait,
207
+ timeout=timeout,
208
+ kill_before=life_cycle_policy.kill_before_same_old_command_running,
209
+ kill_after=life_cycle_policy.kill_after_command_still_running,
210
+ break_on_timeout=life_cycle_policy.break_on_timeout,
211
+ )
200
212
 
201
213
  job_result, stdout, stderr = await dc_shell.dc_exec(container, f'cat /tmp/{log_file}')
202
214
  if job_result != JobResult.GOOD:
203
215
  self.logger.error(Text(f'Error executing command in container {container}: {stderr}'))
204
216
 
205
- if not res.check_result:
217
+ if not res.finished:
206
218
  return ExecTimeout(stdout=stdout, cmd=command)
207
219
 
208
220
  return ExecResult(stdout=stdout, cmd=command)
@@ -9,6 +9,7 @@ from typing import Type
9
9
  from typing import TypeVar
10
10
  from warnings import warn
11
11
 
12
+ from uber_compose.core.docker_compose_shell.types import ExecLifeCyclePolicy
12
13
  from uber_compose.helpers.exec_result import ExecResult
13
14
 
14
15
  from uber_compose.core.docker_compose_shell.interface import TimeOutCheck
@@ -214,12 +215,14 @@ class CommonJsonCli(Generic[TCommandResult]):
214
215
  result_factory: Type[TCommandResult] = CommandResult,
215
216
  cli_client: SystemUberCompose = None,
216
217
  timeout: TimeOutCheck = TimeOutCheck(attempts=10, delay_s=1),
218
+ life_cycle_policy: ExecLifeCyclePolicy = ExecLifeCyclePolicy(),
217
219
  ):
218
220
  self._container = container
219
221
  self._cli_client: SystemUberCompose = cli_client or TheUberCompose()
220
222
  self._parse_json_logs = parse_json_logs
221
223
  self._result_factory = result_factory
222
224
  self._timeout = timeout
225
+ self._life_cycle_policy = life_cycle_policy
223
226
 
224
227
  def _make_result(self, cmd: str, env: dict[str, str], logs: bytes, **kwargs) -> TCommandResult:
225
228
  stdout, stderr = self._parse_json_logs(logs)
@@ -232,6 +235,7 @@ class CommonJsonCli(Generic[TCommandResult]):
232
235
  wait: Callable | ProcessExit | None = ProcessExit(),
233
236
  command_result_extra: dict = None,
234
237
  timeout: TimeOutCheck = None,
238
+ life_cycle_policy: ExecLifeCyclePolicy = None,
235
239
  ) -> TCommandResult:
236
240
  if command_result_extra is None:
237
241
  command_result_extra = {}
@@ -243,12 +247,16 @@ class CommonJsonCli(Generic[TCommandResult]):
243
247
  assert self._container is not None, 'No container specified. Container must be specified either in method call or in CommonJsonCli initialization'
244
248
  container = self._container
245
249
 
250
+ if life_cycle_policy is None:
251
+ life_cycle_policy = self._life_cycle_policy
252
+
246
253
  result = await self._cli_client.exec(
247
254
  container=container,
248
255
  command=command,
249
256
  extra_env=extra_env,
250
257
  wait=wait,
251
258
  timeout=timeout,
259
+ life_cycle_policy=life_cycle_policy,
252
260
  )
253
261
 
254
262
  return self._make_result(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uber-compose
3
- Version: 2.1.5b1
3
+ Version: 2.1.5b3
4
4
  Summary: docker compose testing env orchestrator
5
5
  Home-page: https://github.com/ko10ok/uber-compose
6
6
  Author: Yuriy Sagitov
File without changes
File without changes
File without changes
File without changes