playground-ls-cli 4.14.1.dev8__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 (112) hide show
  1. localstack_cli/__init__.py +0 -0
  2. localstack_cli/cli/__init__.py +10 -0
  3. localstack_cli/cli/console.py +11 -0
  4. localstack_cli/cli/core_plugin.py +12 -0
  5. localstack_cli/cli/exceptions.py +19 -0
  6. localstack_cli/cli/localstack.py +951 -0
  7. localstack_cli/cli/lpm.py +138 -0
  8. localstack_cli/cli/main.py +22 -0
  9. localstack_cli/cli/plugin.py +39 -0
  10. localstack_cli/cli/plugins.py +134 -0
  11. localstack_cli/cli/profiles.py +65 -0
  12. localstack_cli/config.py +1689 -0
  13. localstack_cli/constants.py +165 -0
  14. localstack_cli/logging/__init__.py +0 -0
  15. localstack_cli/logging/format.py +194 -0
  16. localstack_cli/logging/setup.py +142 -0
  17. localstack_cli/packages/__init__.py +25 -0
  18. localstack_cli/packages/api.py +418 -0
  19. localstack_cli/packages/core.py +416 -0
  20. localstack_cli/pro/__init__.py +0 -0
  21. localstack_cli/pro/core/__init__.py +0 -0
  22. localstack_cli/pro/core/bootstrap/__init__.py +1 -0
  23. localstack_cli/pro/core/bootstrap/auth.py +213 -0
  24. localstack_cli/pro/core/bootstrap/dns_utils.py +55 -0
  25. localstack_cli/pro/core/bootstrap/entitlements.py +117 -0
  26. localstack_cli/pro/core/bootstrap/extensions/__init__.py +3 -0
  27. localstack_cli/pro/core/bootstrap/extensions/__main__.py +106 -0
  28. localstack_cli/pro/core/bootstrap/extensions/autoinstall.py +63 -0
  29. localstack_cli/pro/core/bootstrap/extensions/bootstrap.py +97 -0
  30. localstack_cli/pro/core/bootstrap/extensions/repository.py +374 -0
  31. localstack_cli/pro/core/bootstrap/licensingv2.py +1259 -0
  32. localstack_cli/pro/core/bootstrap/pods/__init__.py +0 -0
  33. localstack_cli/pro/core/bootstrap/pods/api_types.py +17 -0
  34. localstack_cli/pro/core/bootstrap/pods/constants.py +26 -0
  35. localstack_cli/pro/core/bootstrap/pods/remotes/__init__.py +0 -0
  36. localstack_cli/pro/core/bootstrap/pods/remotes/api.py +75 -0
  37. localstack_cli/pro/core/bootstrap/pods/remotes/configs.py +69 -0
  38. localstack_cli/pro/core/bootstrap/pods/remotes/params.py +86 -0
  39. localstack_cli/pro/core/bootstrap/pods_client.py +834 -0
  40. localstack_cli/pro/core/cli/__init__.py +0 -0
  41. localstack_cli/pro/core/cli/auth.py +226 -0
  42. localstack_cli/pro/core/cli/aws.py +16 -0
  43. localstack_cli/pro/core/cli/cli.py +99 -0
  44. localstack_cli/pro/core/cli/click_utils.py +21 -0
  45. localstack_cli/pro/core/cli/cloud_pods.py +465 -0
  46. localstack_cli/pro/core/cli/diff_view.py +41 -0
  47. localstack_cli/pro/core/cli/ephemeral.py +199 -0
  48. localstack_cli/pro/core/cli/extensions.py +492 -0
  49. localstack_cli/pro/core/cli/iam.py +180 -0
  50. localstack_cli/pro/core/cli/license.py +90 -0
  51. localstack_cli/pro/core/cli/localstack.py +118 -0
  52. localstack_cli/pro/core/cli/replicator.py +378 -0
  53. localstack_cli/pro/core/cli/state.py +183 -0
  54. localstack_cli/pro/core/cli/tree_view.py +235 -0
  55. localstack_cli/pro/core/config.py +556 -0
  56. localstack_cli/pro/core/constants.py +54 -0
  57. localstack_cli/pro/core/plugins.py +169 -0
  58. localstack_cli/runtime/__init__.py +6 -0
  59. localstack_cli/runtime/exceptions.py +7 -0
  60. localstack_cli/runtime/hooks.py +73 -0
  61. localstack_cli/testing/__init__.py +1 -0
  62. localstack_cli/testing/config.py +4 -0
  63. localstack_cli/utils/__init__.py +0 -0
  64. localstack_cli/utils/analytics/__init__.py +12 -0
  65. localstack_cli/utils/analytics/cli.py +67 -0
  66. localstack_cli/utils/analytics/client.py +111 -0
  67. localstack_cli/utils/analytics/events.py +30 -0
  68. localstack_cli/utils/analytics/logger.py +48 -0
  69. localstack_cli/utils/analytics/metadata.py +250 -0
  70. localstack_cli/utils/analytics/publisher.py +160 -0
  71. localstack_cli/utils/analytics/service_request_aggregator.py +133 -0
  72. localstack_cli/utils/archives.py +271 -0
  73. localstack_cli/utils/batching.py +258 -0
  74. localstack_cli/utils/bootstrap.py +1418 -0
  75. localstack_cli/utils/checksum.py +313 -0
  76. localstack_cli/utils/collections.py +554 -0
  77. localstack_cli/utils/common.py +229 -0
  78. localstack_cli/utils/container_networking.py +142 -0
  79. localstack_cli/utils/container_utils/__init__.py +0 -0
  80. localstack_cli/utils/container_utils/container_client.py +1585 -0
  81. localstack_cli/utils/container_utils/docker_cmd_client.py +987 -0
  82. localstack_cli/utils/container_utils/docker_sdk_client.py +1018 -0
  83. localstack_cli/utils/crypto.py +294 -0
  84. localstack_cli/utils/docker_utils.py +272 -0
  85. localstack_cli/utils/files.py +327 -0
  86. localstack_cli/utils/functions.py +92 -0
  87. localstack_cli/utils/http.py +326 -0
  88. localstack_cli/utils/json.py +219 -0
  89. localstack_cli/utils/net.py +516 -0
  90. localstack_cli/utils/no_exit_argument_parser.py +19 -0
  91. localstack_cli/utils/numbers.py +49 -0
  92. localstack_cli/utils/objects.py +235 -0
  93. localstack_cli/utils/patch.py +260 -0
  94. localstack_cli/utils/platform.py +77 -0
  95. localstack_cli/utils/run.py +514 -0
  96. localstack_cli/utils/server/__init__.py +0 -0
  97. localstack_cli/utils/server/tcp_proxy.py +108 -0
  98. localstack_cli/utils/serving.py +187 -0
  99. localstack_cli/utils/ssl.py +71 -0
  100. localstack_cli/utils/strings.py +245 -0
  101. localstack_cli/utils/sync.py +267 -0
  102. localstack_cli/utils/threads.py +163 -0
  103. localstack_cli/utils/time.py +81 -0
  104. localstack_cli/utils/urls.py +21 -0
  105. localstack_cli/utils/venv.py +100 -0
  106. localstack_cli/utils/xml.py +41 -0
  107. localstack_cli/version.py +34 -0
  108. playground_ls_cli-4.14.1.dev8.dist-info/METADATA +95 -0
  109. playground_ls_cli-4.14.1.dev8.dist-info/RECORD +112 -0
  110. playground_ls_cli-4.14.1.dev8.dist-info/WHEEL +5 -0
  111. playground_ls_cli-4.14.1.dev8.dist-info/entry_points.txt +17 -0
  112. playground_ls_cli-4.14.1.dev8.dist-info/top_level.txt +1 -0
File without changes
@@ -0,0 +1,17 @@
1
+ from enum import Enum
2
+
3
+
4
+ class MergeStrategy(str, Enum):
5
+ """Enumerates the different strategies we can adopt when merging a state into LocalStack."""
6
+
7
+ OVERWRITE = "overwrite"
8
+ """The runtime state is wiped out and the incoming one is loaded."""
9
+ ACCOUNT_REGION_MERGE = "account-region-merge"
10
+ """Services sitting in different account-region pairs are merged. Technically, this level can also have conflicts
11
+ in the account/region-cross attributes."""
12
+ SERVICE_MERGE = "service-merge"
13
+ """Services are merged down to the account-region level if there is no resource overlap. Ideologically, a resource
14
+ is everything that have an ARN in AWS. In the internal implementation of LocalStack, a resource is a key in the
15
+ attribute dictionary of a store or moto backend."""
16
+ # RESOURCE_MERGE = "resource-merge"
17
+ """At this level, we merge everything down to the single AWS resource. This level is not yet implemented."""
@@ -0,0 +1,26 @@
1
+ NIL_PTR = "NIL"
2
+
3
+ # well-defined directory names
4
+ ASSETS_ROOT_DIR = "assets"
5
+ DEFAULT_POD_DIR = "cloudpods"
6
+ OBJ_STORE_DIR = "objects"
7
+
8
+ VERSION_FILE = "version.yaml"
9
+
10
+ # regex pattern for cloud pod names
11
+ POD_NAME_PATTERN = "^[a-zA-Z0-9_-]+$"
12
+ # regex pattern for cloud pod versions - currently only numeric versions supported
13
+ POD_VERSION_PATTERN = r"\d+"
14
+
15
+ # The name of the zip file containing cloud pod state (i.e., pickled stores and assets)
16
+ STATE_ZIP = "pod_state"
17
+ # The name of the zip file containing the full version history
18
+ VERSIONS_ARCHIVE = "version"
19
+ # Compression format for the cloud pod
20
+ COMPRESSION_FORMAT = "zip"
21
+
22
+ # well-defined file names
23
+ VERSION_SPACE_DIRS = [OBJ_STORE_DIR, VERSION_FILE]
24
+
25
+ # header name that indicates internal requests made to LocalStack
26
+ INTERNAL_REQUEST_PARAMS_HEADER = "x-localstack-data"
@@ -0,0 +1,75 @@
1
+ import json
2
+ from abc import ABC, abstractmethod
3
+
4
+ import requests
5
+ from localstack_cli import config
6
+ from localstack_cli.pro.core.bootstrap.pods.constants import INTERNAL_REQUEST_PARAMS_HEADER
7
+ from localstack_cli.pro.core.constants import API_PATH_PODS
8
+
9
+
10
+ class CloudPodsRemotesInterface(ABC):
11
+ """Service interface for the remote CRUD operations."""
12
+
13
+ @abstractmethod
14
+ def create_remote(self, name: str, protocols: list[str], remote_url: str | None = None) -> None:
15
+ """Creates a new remote with a given name.
16
+ :param name: The name of the remote.
17
+ :param protocols: The protocols supported by the remote.
18
+ :param remote_url: The URL of the remote.
19
+ TODO: think about security: we should check if the URL is either (1) localhost, or (2) using HTTPS.
20
+ """
21
+
22
+ @abstractmethod
23
+ def delete_remote(self, name: str) -> None:
24
+ """Deletes a named remote."""
25
+
26
+ @abstractmethod
27
+ def get_remote(self, name: str) -> dict[str, str]:
28
+ """Returns a named remote."""
29
+
30
+ @abstractmethod
31
+ def get_remotes(self) -> list[dict[str, str]]:
32
+ """Returns a list of all remotes."""
33
+
34
+
35
+ class CloudPodsRemotesClient(CloudPodsRemotesInterface):
36
+ @property
37
+ def endpoint(self):
38
+ return f"{config.external_service_url()}{API_PATH_PODS}/remotes"
39
+
40
+ def create_remote(self, name: str, protocols: list[str], remote_url: str | None = None) -> None:
41
+ params = {"name": name, "protocols": protocols, "remote_url": remote_url}
42
+ response = self._client.post(
43
+ url=f"{self.endpoint}/{name}",
44
+ data=json.dumps(params),
45
+ headers={"Content-Type": "application/json"},
46
+ )
47
+ if not response.ok:
48
+ raise Exception(f"Failed to create remote: {response.content}")
49
+
50
+ def delete_remote(self, name: str) -> None:
51
+ response = self._client.delete(url=f"{self.endpoint}/{name}")
52
+ if not response.ok:
53
+ raise Exception(f"Failed to delete remote: {response.content}")
54
+
55
+ def get_remotes(self) -> list[dict[str, str]]:
56
+ response = self._client.get(url=self.endpoint)
57
+ if not response.ok:
58
+ raise Exception(f"Failed to get list of remotes: {response.content}")
59
+ remotes = json.loads(response.content)
60
+ return remotes.get("remotes", [])
61
+
62
+ def get_remote(self, name: str) -> dict[str, str]:
63
+ response = self._client.get(url=f"{self.endpoint}/{name}")
64
+ if not response.ok:
65
+ raise Exception(f"Failed to get remote: {response.content}")
66
+ remote = json.loads(response.content)
67
+ return remote
68
+
69
+ @property
70
+ def _client(self) -> requests.Session:
71
+ """Return an HTTP client session, adding default headers for all requests, as required"""
72
+ session = requests.Session()
73
+ # TODO: temporary fix to bypass Gateway 503 responses on LocalStack container shutdown
74
+ session.headers.update({INTERNAL_REQUEST_PARAMS_HEADER: "{}"})
75
+ return session
@@ -0,0 +1,69 @@
1
+ from dataclasses import asdict, dataclass, field
2
+ from urllib.parse import quote, urlparse
3
+
4
+ DEFAULT_REMOTE_SCHEME = "platform"
5
+
6
+
7
+ @dataclass
8
+ class RemoteConfig:
9
+ """
10
+ Defines the configurations of a specific remote storage backend, used to perform cloud pods remote operations.
11
+
12
+ Note: For now, the remote config only consists of a URL, which would encapsulate all the details required to
13
+ interact with the remote (incl. auth tokens, etc). Over time, we may think of introducing a way to add
14
+ more fine-grained configurations for remotes.
15
+
16
+ Note: Remote URLs may contain `{..}` placeholders like `proto://{user}:{secret}@host', which will then
17
+ get replaced with concrete user parameters specified via `RemoteConfigParams` at runtime.
18
+
19
+ For the special case of our own remote platform (which is the default for remote operations), specifying the URL
20
+ is not required, and the access credentials are retrieved from the token cache populated on "localstack login".
21
+ """
22
+
23
+ remote_url: str
24
+ """The URL of the remote"""
25
+
26
+ @property
27
+ def scheme(self) -> str:
28
+ scheme = DEFAULT_REMOTE_SCHEME
29
+ if self.remote_url:
30
+ scheme = urlparse(self.remote_url).scheme
31
+ return scheme
32
+
33
+
34
+ @dataclass
35
+ class RemoteConfigParams:
36
+ """
37
+ Runtime parameters for cloud pod remotes, extracted from the user environment for remote operations.
38
+
39
+ The remote parameters typically contain credentials which are specified by the user and are then rendered
40
+ into the remote URL at runtime (to keep secret values ephemeral and avoid persisting them within URLs).
41
+ """
42
+
43
+ remote_name: str
44
+ """The name of the remote"""
45
+ remote_params: dict[str, str] = field(default_factory=dict)
46
+ """The runtime parameters of the remote"""
47
+
48
+ def render_url(self, remote_url: str) -> str:
49
+ """
50
+ Render the given remote URL template (e.g., 's3://{key}:{secret}@bucket') with the remote params.
51
+ """
52
+ if self.remote_params:
53
+ remote_params_escaped = {k: quote(v or "") for k, v in self.remote_params.items()}
54
+ remote_url = remote_url.format(**remote_params_escaped)
55
+ try:
56
+ # check if all placeholders have been replaced
57
+ remote_url.format()
58
+ except Exception as e:
59
+ raise Exception(
60
+ f"Missing parameters for cloud pod remote URL template: {remote_url}"
61
+ ) from e
62
+ return remote_url
63
+
64
+ def to_dict(self) -> dict:
65
+ return asdict(self)
66
+
67
+ @classmethod
68
+ def from_dict(cls, params: dict) -> "RemoteConfigParams":
69
+ return cls(**params)
@@ -0,0 +1,86 @@
1
+ import logging
2
+ import os
3
+ from collections.abc import Callable
4
+ from urllib.parse import urlparse
5
+
6
+ from localstack_cli.pro.core.bootstrap.pods.remotes.configs import DEFAULT_REMOTE_SCHEME
7
+
8
+ LOG = logging.getLogger(__name__)
9
+
10
+ PARAM_ACCESS_KEY_ID = "access_key_id"
11
+ PARAM_SECRET_ACCESS_KEY = "secret_access_key"
12
+ PARAM_SESSION_TOKEN = "session_token"
13
+
14
+
15
+ def _get_aws_credentials_from_boto_session() -> dict[str, str] | None:
16
+ try:
17
+ import boto3
18
+
19
+ session = boto3.session.Session()
20
+ credentials = session.get_credentials()
21
+ return {
22
+ PARAM_ACCESS_KEY_ID: credentials.access_key,
23
+ PARAM_SECRET_ACCESS_KEY: credentials.secret_key,
24
+ PARAM_SESSION_TOKEN: credentials.token,
25
+ }
26
+ except Exception as e:
27
+ LOG.debug("Unable to extract remote parameters: %s", e)
28
+
29
+
30
+ def get_s3_remote_params() -> dict[str, str]:
31
+ """
32
+ Returns the AWS credentials necessary to create the bucket storing the pods artifacts.
33
+ It first tries to fetch the credentials from a boto3 session. If this is not possible (e.g., boto3 not installed
34
+ on the host), it looks in the environment.
35
+ """
36
+ if params := _get_aws_credentials_from_boto_session():
37
+ return params
38
+
39
+ aws_access_key_id = os.getenv("AWS_ACCESS_KEY_ID")
40
+ aws_secret_access_key = os.getenv("AWS_SECRET_ACCESS_KEY")
41
+ aws_session_token = os.getenv("AWS_SESSION_TOKEN")
42
+
43
+ if not aws_access_key_id or not aws_secret_access_key:
44
+ raise Exception(
45
+ "Please export AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in the environment"
46
+ )
47
+
48
+ params = {
49
+ PARAM_ACCESS_KEY_ID: aws_access_key_id,
50
+ PARAM_SECRET_ACCESS_KEY: aws_secret_access_key,
51
+ }
52
+ if aws_session_token:
53
+ params[PARAM_SESSION_TOKEN] = aws_session_token
54
+ return params
55
+
56
+
57
+ def get_oras_remote_params() -> dict[str, str]:
58
+ # note: allow case-insensitive env. variables (all upper- or lower-case)
59
+ oras_username = os.getenv("ORAS_USERNAME") or os.getenv("oras_username")
60
+ oras_password = os.getenv("ORAS_PASSWORD") or os.getenv("oras_password")
61
+ if not oras_username or not oras_password:
62
+ raise Exception("Please specify ORAS_USERNAME and ORAS_PASSWORD in the environment")
63
+ return {"oras_username": oras_username, "oras_password": oras_password}
64
+
65
+
66
+ def get_platform_remote_params() -> dict[str, str]:
67
+ # note: allow case-insensitive env. variables (all upper- or lower-case)
68
+ auth_token = os.getenv("LOCALSTACK_AUTH_TOKEN")
69
+ bearer_token = os.getenv("LOCALSTACK_BEARER_TOKEN")
70
+ api_key = os.getenv("LOCALSTACK_API_KEY")
71
+ if not auth_token and not api_key and not bearer_token:
72
+ raise Exception("Please specify LOCALSTACK_AUTH_TOKEN in the environment")
73
+ return {"api_key": api_key, "auth_token": auth_token, "bearer_token": bearer_token}
74
+
75
+
76
+ remotes_protocols: dict[str, Callable[[], dict]] = {
77
+ "s3": get_s3_remote_params,
78
+ "oras": get_oras_remote_params,
79
+ "platform": get_platform_remote_params,
80
+ }
81
+
82
+
83
+ def get_remote_params_callable(url: str) -> Callable[[], dict] | None:
84
+ """Returns a Callable that retrieves the remote parameters for a given URL."""
85
+ protocol = urlparse(url).scheme or DEFAULT_REMOTE_SCHEME
86
+ return remotes_protocols.get(protocol, None)