aws-annoying 0.5.0__py3-none-any.whl → 0.6.0__py3-none-any.whl

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 (31) hide show
  1. aws_annoying/cli/app.py +81 -0
  2. aws_annoying/cli/ecs/__init__.py +3 -0
  3. aws_annoying/cli/ecs/_app.py +9 -0
  4. aws_annoying/cli/{ecs_task_definition_lifecycle.py → ecs/task_definition_lifecycle.py} +18 -13
  5. aws_annoying/cli/ecs/wait_for_deployment.py +94 -0
  6. aws_annoying/cli/load_variables.py +22 -22
  7. aws_annoying/cli/logging_handler.py +52 -0
  8. aws_annoying/cli/main.py +1 -1
  9. aws_annoying/cli/mfa/configure.py +21 -12
  10. aws_annoying/cli/session_manager/_common.py +1 -32
  11. aws_annoying/cli/session_manager/install.py +8 -5
  12. aws_annoying/cli/session_manager/port_forward.py +22 -12
  13. aws_annoying/cli/session_manager/start.py +13 -5
  14. aws_annoying/cli/session_manager/stop.py +9 -7
  15. aws_annoying/ecs/__init__.py +17 -0
  16. aws_annoying/ecs/common.py +8 -0
  17. aws_annoying/ecs/deployment_waiter.py +274 -0
  18. aws_annoying/ecs/errors.py +14 -0
  19. aws_annoying/{mfa.py → mfa_config.py} +7 -2
  20. aws_annoying/session_manager/session_manager.py +2 -4
  21. aws_annoying/session_manager/shortcuts.py +10 -6
  22. aws_annoying/utils/ec2.py +36 -0
  23. aws_annoying/utils/platform.py +11 -0
  24. aws_annoying/utils/timeout.py +88 -0
  25. aws_annoying/{variables.py → variable_loader.py} +11 -16
  26. {aws_annoying-0.5.0.dist-info → aws_annoying-0.6.0.dist-info}/METADATA +47 -2
  27. aws_annoying-0.6.0.dist-info/RECORD +41 -0
  28. aws_annoying-0.5.0.dist-info/RECORD +0 -31
  29. {aws_annoying-0.5.0.dist-info → aws_annoying-0.6.0.dist-info}/WHEEL +0 -0
  30. {aws_annoying-0.5.0.dist-info → aws_annoying-0.6.0.dist-info}/entry_points.txt +0 -0
  31. {aws_annoying-0.5.0.dist-info → aws_annoying-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,88 @@
1
+ from __future__ import annotations
2
+
3
+ import signal
4
+ from functools import wraps
5
+ from typing import TYPE_CHECKING, Callable, Optional, TypeVar, cast
6
+
7
+ from pydantic import PositiveInt, validate_call
8
+
9
+ from aws_annoying.utils.platform import is_windows
10
+
11
+ if TYPE_CHECKING:
12
+ from types import FrameType
13
+ from typing import Any
14
+
15
+
16
+ class OperationTimeoutError(Exception):
17
+ """Operation timed out."""
18
+
19
+
20
+ _F = TypeVar("_F", bound=Callable)
21
+
22
+
23
+ class Timeout:
24
+ """Timeout handler utilizing signals.
25
+
26
+ This utility relies on Unix signals (`signal.SIGALRM`). The behavior will be dummied
27
+ to do nothing on Windows OS.
28
+ """
29
+
30
+ @validate_call
31
+ def __init__(self, seconds: Optional[PositiveInt]) -> None:
32
+ """Initialize timeout handler.
33
+
34
+ Args:
35
+ seconds: The timeout in seconds. `None` means no timeout,
36
+ allowing the function to run normally.
37
+
38
+ """
39
+ self.timeout_seconds = seconds
40
+
41
+ self._signal_handler_registered = False
42
+
43
+ def _set_signal_handler(self) -> None:
44
+ if is_windows() or self.timeout_seconds is None:
45
+ return
46
+
47
+ signal.signal(signal.SIGALRM, self._handler)
48
+ signal.alarm(self.timeout_seconds)
49
+ self._signal_handler_registered = True
50
+
51
+ def _handler(self, signum: int, frame: FrameType | None) -> Any: # noqa: ARG002
52
+ msg = "Timeout reached"
53
+ raise OperationTimeoutError(msg)
54
+
55
+ def _reset_signal_handler(self) -> None:
56
+ if is_windows() or not self._signal_handler_registered:
57
+ return
58
+
59
+ signal.signal(signal.SIGALRM, signal.SIG_IGN)
60
+ signal.alarm(0)
61
+ self._signal_handler_registered = False
62
+
63
+ def __call__(self, func: _F) -> _F:
64
+ """Decorator to set a timeout for a function.
65
+
66
+ Please note, using this decorator in nested functions may not work properly as
67
+ the signal handler for outer functions may not be resumed correctly.
68
+
69
+ Raises:
70
+ OperationTimeoutError: When timeout is reached.
71
+ """
72
+
73
+ @wraps(func)
74
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
75
+ self._set_signal_handler()
76
+ try:
77
+ return func(*args, **kwargs)
78
+ finally:
79
+ self._reset_signal_handler()
80
+
81
+ return cast("_F", wrapper)
82
+
83
+ def __enter__(self) -> None:
84
+ self._set_signal_handler()
85
+
86
+ def __exit__(self, *args: object) -> Any:
87
+ self._reset_signal_handler()
88
+ return False # Re-raise
@@ -2,17 +2,17 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import json
5
+ import logging
5
6
  from typing import Any, TypedDict
6
7
 
7
8
  import boto3
8
9
 
10
+ logger = logging.getLogger(__name__)
11
+
9
12
  # Type aliases for readability
10
13
  _ARN = str
11
14
  _Variables = dict[str, Any]
12
15
 
13
- # TODO(lasuillard): Need some refactoring (with #2, #3)
14
- # TODO(lasuillard): Put some logging
15
-
16
16
 
17
17
  class _LoadStatsDict(TypedDict):
18
18
  secrets: int
@@ -20,14 +20,13 @@ class _LoadStatsDict(TypedDict):
20
20
 
21
21
 
22
22
  class VariableLoader: # noqa: D101
23
- def __init__(self, *, dry_run: bool) -> None:
24
- """Initialize the VariableLoader.
23
+ def __init__(self, *, session: boto3.session.Session | None = None) -> None:
24
+ """Initialize variable loader.
25
25
 
26
26
  Args:
27
- dry_run: Whether to run in dry-run mode.
28
- console: Rich console instance.
27
+ session: Boto3 session to use for AWS operations.
29
28
  """
30
- self.dry_run = dry_run
29
+ self.session = session or boto3.session.Session()
31
30
 
32
31
  # TODO(lasuillard): Currently not using pagination (do we need more than 10-20 secrets or parameters each?)
33
32
  # ; consider adding it if needed
@@ -54,12 +53,8 @@ class VariableLoader: # noqa: D101
54
53
  # Retrieve variables from AWS resources
55
54
  secrets: dict[str, _Variables]
56
55
  parameters: dict[str, _Variables]
57
- if self.dry_run:
58
- secrets = {idx: {} for idx, _ in secrets_map.items()}
59
- parameters = {idx: {} for idx, _ in parameters_map.items()}
60
- else:
61
- secrets = self._retrieve_secrets(secrets_map)
62
- parameters = self._retrieve_parameters(parameters_map)
56
+ secrets = self._retrieve_secrets(secrets_map)
57
+ parameters = self._retrieve_parameters(parameters_map)
63
58
 
64
59
  load_stats: _LoadStatsDict = {
65
60
  "secrets": len(secrets),
@@ -79,7 +74,7 @@ class VariableLoader: # noqa: D101
79
74
  if not secrets_map:
80
75
  return {}
81
76
 
82
- secretsmanager = boto3.client("secretsmanager")
77
+ secretsmanager = self.session.client("secretsmanager")
83
78
 
84
79
  # Retrieve the secrets
85
80
  arns = list(secrets_map.values())
@@ -108,7 +103,7 @@ class VariableLoader: # noqa: D101
108
103
  if not parameters_map:
109
104
  return {}
110
105
 
111
- ssm = boto3.client("ssm")
106
+ ssm = self.session.client("ssm")
112
107
 
113
108
  # Retrieve the parameters
114
109
  parameter_names = list(parameters_map.values())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aws-annoying
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: Utils to handle some annoying AWS tasks.
5
5
  Project-URL: Homepage, https://github.com/lasuillard/aws-annoying
6
6
  Project-URL: Repository, https://github.com/lasuillard/aws-annoying.git
@@ -22,13 +22,15 @@ Requires-Dist: types-requests>=2.31.0.6; extra == 'dev'
22
22
  Provides-Extra: test
23
23
  Requires-Dist: coverage<7.9,>=7.6; extra == 'test'
24
24
  Requires-Dist: moto[ecs,secretsmanager,server,ssm]~=5.1.1; extra == 'test'
25
- Requires-Dist: pytest-cov~=6.0.0; extra == 'test'
25
+ Requires-Dist: pytest-cov<6.2,>=6.0; extra == 'test'
26
26
  Requires-Dist: pytest-env~=1.1.1; extra == 'test'
27
27
  Requires-Dist: pytest-snapshot>=0.9.0; extra == 'test'
28
28
  Requires-Dist: pytest-sugar~=1.0.0; extra == 'test'
29
29
  Requires-Dist: pytest-xdist>=3.6.1; extra == 'test'
30
30
  Requires-Dist: pytest~=8.3.2; extra == 'test'
31
31
  Requires-Dist: testcontainers[localstack]>=4.9.2; extra == 'test'
32
+ Requires-Dist: toml>=0.10.2; extra == 'test'
33
+ Requires-Dist: types-toml>=0.10.8.20240310; extra == 'test'
32
34
  Description-Content-Type: text/markdown
33
35
 
34
36
  # aws-annoying
@@ -39,3 +41,46 @@ Description-Content-Type: text/markdown
39
41
  ![PyPI - Version](https://img.shields.io/pypi/v/aws-annoying)
40
42
 
41
43
  Utils to handle some annoying AWS tasks.
44
+
45
+ ## ❓ About
46
+
47
+ This project aims to provide a set of utilities and examples to help with some annoying tasks when working with AWS.
48
+
49
+ Major directories of the project:
50
+
51
+ - **aws_annoying** Python package containing CLI and utility functions.
52
+ - **console** Utilities to help working with AWS Console.
53
+ - **examples** Examples of how to use the package.
54
+
55
+ ## 🚀 Installation
56
+
57
+ It is recommended to use [pipx](https://pipx.pypa.io/stable/) to install `aws-annoying`:
58
+
59
+ ```bash
60
+ $ pipx install aws-annoying
61
+ $ aws-annoying --help
62
+
63
+ Usage: aws-annoying [OPTIONS] COMMAND [ARGS]...
64
+
65
+ ...
66
+ ```
67
+
68
+ Available commands:
69
+
70
+ - **ecs** ECS utilities.
71
+ - **task-definition-lifecycle** Help to manage ECS task definitions lifecycle.
72
+ - **wait-for-deployment** Wait for ECS deployment to complete.
73
+ - **load-variables** Wrapper command to run command with variables from AWS resources injected as environment variables.
74
+ - **mfa** Commands to manage MFA authentication.
75
+ - **configure** Configure AWS profile for MFA.
76
+ - **session-manager** AWS Session Manager CLI utilities.
77
+ - **install** Install AWS Session Manager plugin.
78
+ - **port-forward** Start a port forwarding session using AWS Session Manager.
79
+ - **start** Start new session.
80
+ - **stop** Stop running session for PID file.
81
+
82
+ Please refer to the CLI help for more information about the available commands and options.
83
+
84
+ ## 💖 Contributing
85
+
86
+ Any feedback, suggestions or contributions are welcome! Feel free to open an issue or a pull request.
@@ -0,0 +1,41 @@
1
+ aws_annoying/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ aws_annoying/mfa_config.py,sha256=z0GpRhLHEWaaXbECV4Ei4oNM1WCFoEZAxCIPbpY4Ymc,2200
3
+ aws_annoying/variable_loader.py,sha256=N9qPPHG6mzSIIHrWJnJ_FV5kKZxssOaTHoAQEwiDE3s,4569
4
+ aws_annoying/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ aws_annoying/cli/app.py,sha256=6opsAfIFGPnUSK68s7sEnFzLhipnevfP2cDJ0yj7Lh0,2366
6
+ aws_annoying/cli/load_variables.py,sha256=83RGt5eA_TJtza3kyLXoSM_A3lfQs6TNC2TCrWYia_I,5032
7
+ aws_annoying/cli/logging_handler.py,sha256=JPsZePV3YH9e1nLv0Q3fqSeXSEfZ5cGJo6eLK2F4oxE,1426
8
+ aws_annoying/cli/main.py,sha256=bU4Gxic5_3qrrd8l9eN709-D4o_OHgrdH91FS9Xs8zI,477
9
+ aws_annoying/cli/ecs/__init__.py,sha256=IxfaMXcGU6WTHE_RXj-aitXtSg25j5m3HGTG9O02GjI,125
10
+ aws_annoying/cli/ecs/_app.py,sha256=izD0VL55i7oG-2CtWCV21bSoAeE-DZbxyJ5pi6VXhjU,200
11
+ aws_annoying/cli/ecs/task_definition_lifecycle.py,sha256=W7zr8zEPjjHgss9Tnb3QMcJ_45Yb9SJ5D1B315vb9kc,2803
12
+ aws_annoying/cli/ecs/wait_for_deployment.py,sha256=0lzl5t0TOvJJeMxIA6if2TbG7bJFf6JulhPHZqNXjFM,3169
13
+ aws_annoying/cli/mfa/__init__.py,sha256=rbEGhw5lOQZV_XAc3nSbo56JVhsSPpeOgEtiAy9qzEA,50
14
+ aws_annoying/cli/mfa/_app.py,sha256=Ub7gxb6kGF3Ve1ucQSOjHmc4jAu8mxgegcXsIbOzLLQ,189
15
+ aws_annoying/cli/mfa/configure.py,sha256=s2SCz7gzvIE9mJM7w95JPwoGhuQrgkFhjUd6qjD169k,3957
16
+ aws_annoying/cli/session_manager/__init__.py,sha256=FkT6jT6OXduOURN61d-U6hgd-XluQbvuVtKXXiXgSEk,105
17
+ aws_annoying/cli/session_manager/_app.py,sha256=OVOHW0iyKzunvaqLhjoseHw1-WxJ1gGb7QmiyAEezyY,221
18
+ aws_annoying/cli/session_manager/_common.py,sha256=Uj-MF7z8Qntd24Z03xxE-jSKcgrsd8xl41E6db4qCtY,711
19
+ aws_annoying/cli/session_manager/install.py,sha256=VIk6313jUf6THwvs06AOUQwhTjzCGCcvDXMxyz0BcgE,1477
20
+ aws_annoying/cli/session_manager/port_forward.py,sha256=upsUsd7MkUfaAP3o0ZK6N-SkOBnr1ogwqYozG4TDTzY,4331
21
+ aws_annoying/cli/session_manager/start.py,sha256=1Q-WFvbQkMgVntwIrM2HfpUKmVL38aFrjJjG3aA0fzU,1447
22
+ aws_annoying/cli/session_manager/stop.py,sha256=QjjOmmhZr_0IInhOyHvSlodk7Nx4qu9EtrRw4kl8Hks,1535
23
+ aws_annoying/ecs/__init__.py,sha256=Bohwe4-jxF1cxQmErCXl0l5ma08HpWmV2PqdAS-gf4w,432
24
+ aws_annoying/ecs/common.py,sha256=TvP27SEvdIBnA92Oude-oDCy1SuaYNdtpokkbpZmdzo,139
25
+ aws_annoying/ecs/deployment_waiter.py,sha256=e3xWShvr9piraoEMJdZun2GuffkyvTI76-riECfoe9A,9936
26
+ aws_annoying/ecs/errors.py,sha256=n9j_h1MDUV6IVabKgwbCVAiPZQNJDJ5rVRHA82Je5QQ,429
27
+ aws_annoying/session_manager/__init__.py,sha256=IENviL3ux2LF7o9xFGYEiqaGw03hxnyNX2btbB1xyEU,318
28
+ aws_annoying/session_manager/errors.py,sha256=YioKlRtZ-GUP0F_ts_ebw7-HYkxe8mTes6HK821Kuiw,353
29
+ aws_annoying/session_manager/session_manager.py,sha256=pUsyJ_w9UzdIfHA2Z8kU6UcZxOqypFXH1rl6pDytdqo,12046
30
+ aws_annoying/session_manager/shortcuts.py,sha256=Yn4wCl43lfttrZ7GbzfGua2jZHe5Fe6ClEy4ikg-Q_s,2143
31
+ aws_annoying/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ aws_annoying/utils/debugger.py,sha256=UFllDCGI2gPtwo1XS5vqw0qyR6bYr7XknmBwSxalKIc,754
33
+ aws_annoying/utils/downloader.py,sha256=aB5RzT-LpbFX24-2HXlAkdgVowc4TR9FWT_K8WwZ1BE,1923
34
+ aws_annoying/utils/ec2.py,sha256=RjEA5eO53c-H6VE6cZBeB1RJo1rxpDQFhbZTYdANbs8,1062
35
+ aws_annoying/utils/platform.py,sha256=TBIzCzYiFj36HmndZedegvFlxPSNtBQyAxzuwelvxNg,985
36
+ aws_annoying/utils/timeout.py,sha256=PjfFtiLALh7lQvchtMYOfjTNrfuZwCaeaPKW16EpM5c,2483
37
+ aws_annoying-0.6.0.dist-info/METADATA,sha256=68sKE-Atya0ibgT1ljJsaKHpnKXHDq-x7EdUy0yRIqI,3503
38
+ aws_annoying-0.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
39
+ aws_annoying-0.6.0.dist-info/entry_points.txt,sha256=DcKE5V0WvVJ8wUOHxyUz1yLAJOuuJUgRPlMcQ4O7jEs,66
40
+ aws_annoying-0.6.0.dist-info/licenses/LICENSE,sha256=Q5GkvYijQ2KTQ-QWhv43ilzCno4ZrzrEuATEQZd9rYo,1067
41
+ aws_annoying-0.6.0.dist-info/RECORD,,
@@ -1,31 +0,0 @@
1
- aws_annoying/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- aws_annoying/mfa.py,sha256=m6-V1bWeUWsAmRddl-lv13mPCMnftoPzJoNnZ0kiaWQ,2007
3
- aws_annoying/variables.py,sha256=a9cMS9JU-XA2h1tztO7ofixoDEpqtS_eVEiWrQ75mTo,4761
4
- aws_annoying/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- aws_annoying/cli/app.py,sha256=sp50uVoAl4D6Wk3DFpzKZzSsxmSxNYejFxm62b_Kxps,201
6
- aws_annoying/cli/ecs_task_definition_lifecycle.py,sha256=O36Bf5LBnVJNyYmdlUxhtsIHNoxky1t5YacAXiL9UEI,2803
7
- aws_annoying/cli/load_variables.py,sha256=eWNByUEc1ijF8uCe_egdAnjWxfMNCZeVr0vtTtQLe3Y,5086
8
- aws_annoying/cli/main.py,sha256=TSzPeMkgIgKFf3bom_vDkFYK0bHF1r5K9ADreZUV3k4,503
9
- aws_annoying/cli/mfa/__init__.py,sha256=rbEGhw5lOQZV_XAc3nSbo56JVhsSPpeOgEtiAy9qzEA,50
10
- aws_annoying/cli/mfa/_app.py,sha256=Ub7gxb6kGF3Ve1ucQSOjHmc4jAu8mxgegcXsIbOzLLQ,189
11
- aws_annoying/cli/mfa/configure.py,sha256=vsoHfTVFF2dPgiYsp2L-EkMwtAA0_-tVwFd6Wv6DscU,3746
12
- aws_annoying/cli/session_manager/__init__.py,sha256=FkT6jT6OXduOURN61d-U6hgd-XluQbvuVtKXXiXgSEk,105
13
- aws_annoying/cli/session_manager/_app.py,sha256=OVOHW0iyKzunvaqLhjoseHw1-WxJ1gGb7QmiyAEezyY,221
14
- aws_annoying/cli/session_manager/_common.py,sha256=u23F4mJOHWHphLYL1gOAh8J3a_Odyk4VVvI175KWmzg,1616
15
- aws_annoying/cli/session_manager/install.py,sha256=zcQi91xVFKhbSOD4VBc6YG9-fDnhymVyK63PlITdxug,1445
16
- aws_annoying/cli/session_manager/port_forward.py,sha256=J8_CIrTsbcOYRYOdHkdz81dkaNWxI_l70E8gyJ-Ukh8,4192
17
- aws_annoying/cli/session_manager/start.py,sha256=pPS0jKuURGTX-WTix3owqqisX-bmCydqfyqC0kFGnt8,1358
18
- aws_annoying/cli/session_manager/stop.py,sha256=ttU6nlbVgBkZDtY-DwUyCstv5TFtat5TljkyuY8QICU,1482
19
- aws_annoying/session_manager/__init__.py,sha256=IENviL3ux2LF7o9xFGYEiqaGw03hxnyNX2btbB1xyEU,318
20
- aws_annoying/session_manager/errors.py,sha256=YioKlRtZ-GUP0F_ts_ebw7-HYkxe8mTes6HK821Kuiw,353
21
- aws_annoying/session_manager/session_manager.py,sha256=myZxY_WE4akdlTsH1mOvf0Ublwg-hf1vEkEcmdZyYSU,12147
22
- aws_annoying/session_manager/shortcuts.py,sha256=uFRPGia_5gqfBDxwOjmLg7UFzhvkSFUqopWuzN5_kbA,1973
23
- aws_annoying/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- aws_annoying/utils/debugger.py,sha256=UFllDCGI2gPtwo1XS5vqw0qyR6bYr7XknmBwSxalKIc,754
25
- aws_annoying/utils/downloader.py,sha256=aB5RzT-LpbFX24-2HXlAkdgVowc4TR9FWT_K8WwZ1BE,1923
26
- aws_annoying/utils/platform.py,sha256=h3DUWmTMM-_4TfTWNqY0uNqyVsBjAuMm2DEbG-daxe8,742
27
- aws_annoying-0.5.0.dist-info/METADATA,sha256=kHaGAHqfkZ8Ip4NzcLbE7Bh01oA1CvoTsUa3Ljx1ctU,1916
28
- aws_annoying-0.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
29
- aws_annoying-0.5.0.dist-info/entry_points.txt,sha256=DcKE5V0WvVJ8wUOHxyUz1yLAJOuuJUgRPlMcQ4O7jEs,66
30
- aws_annoying-0.5.0.dist-info/licenses/LICENSE,sha256=Q5GkvYijQ2KTQ-QWhv43ilzCno4ZrzrEuATEQZd9rYo,1067
31
- aws_annoying-0.5.0.dist-info/RECORD,,