diaspora-event-sdk 0.2.4__py3-none-any.whl → 0.2.6__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.
@@ -0,0 +1,119 @@
1
+ # Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ import base64
5
+ # import logging
6
+ from datetime import datetime, timezone
7
+ from urllib.parse import parse_qs, urlparse
8
+
9
+ # import boto3
10
+ # import botocore.session
11
+ # import pkg_resources
12
+ from .botocore.auth import SigV4QueryAuth
13
+ from .botocore.awsrequest import AWSRequest
14
+ # from botocore.config import Config
15
+ from .botocore.credentials import Credentials
16
+
17
+ ENDPOINT_URL_TEMPLATE = "https://kafka.{}.amazonaws.com/"
18
+ DEFAULT_TOKEN_EXPIRY_SECONDS = 900
19
+ DEFAULT_STS_SESSION_NAME = "MSKSASLDefaultSession"
20
+ ACTION_TYPE = "Action"
21
+ ACTION_NAME = "kafka-cluster:Connect"
22
+ SIGNING_NAME = "kafka-cluster"
23
+ USER_AGENT_KEY = "User-Agent"
24
+ LIB_NAME = "aws-msk-iam-sasl-signer-python"
25
+
26
+
27
+ def __get_user_agent__():
28
+ return (f"{LIB_NAME}/1.0.1")
29
+
30
+
31
+ def __get_expiration_time_ms(request):
32
+ """
33
+ Private function that parses the url and gets the expiration time
34
+
35
+ Args: request (AWSRequest): The signed aws request object
36
+ """
37
+ # Parse the signed request
38
+ parsed_url = urlparse(request.url)
39
+ parsed_ul_params = parse_qs(parsed_url.query)
40
+ parsed_signing_time = datetime.strptime(parsed_ul_params['X-Amz-Date'][0],
41
+ "%Y%m%dT%H%M%SZ")
42
+
43
+ # Make the datetime object timezone-aware
44
+ signing_time = parsed_signing_time.replace(tzinfo=timezone.utc)
45
+
46
+ # Convert the Unix timestamp to milliseconds
47
+ expiration_timestamp_seconds = int(
48
+ signing_time.timestamp()) + DEFAULT_TOKEN_EXPIRY_SECONDS
49
+
50
+ # Get lifetime of token
51
+ expiration_timestamp_ms = expiration_timestamp_seconds * 1000
52
+
53
+ return expiration_timestamp_ms
54
+
55
+
56
+ def __construct_auth_token(region, aws_credentials):
57
+ """
58
+ Private function that constructs the authorization token using IAM
59
+ Credentials.
60
+
61
+ Args: region (str): The AWS region where the cluster is located.
62
+ aws_credentials (dict): The credentials to be used to generate signed
63
+ url. Returns: str: A base64-encoded authorization token.
64
+ """
65
+ # Validate credentials are not empty
66
+ if not aws_credentials.access_key or not aws_credentials.secret_key:
67
+ raise ValueError("AWS Credentials can not be empty")
68
+
69
+ # Extract endpoint URL
70
+ endpoint_url = ENDPOINT_URL_TEMPLATE.format(region)
71
+
72
+ # Set up resource path and query parameters
73
+ query_params = {ACTION_TYPE: ACTION_NAME}
74
+
75
+ # Create SigV4 instance
76
+ sig_v4 = SigV4QueryAuth(
77
+ aws_credentials, SIGNING_NAME, region,
78
+ expires=DEFAULT_TOKEN_EXPIRY_SECONDS
79
+ )
80
+
81
+ # Create request with url and parameters
82
+ request = AWSRequest(method="GET", url=endpoint_url, params=query_params)
83
+
84
+ # Add auth to the request and prepare the request
85
+ sig_v4.add_auth(request)
86
+ query_params = {USER_AGENT_KEY: __get_user_agent__()}
87
+ request.params = query_params
88
+ prepped = request.prepare()
89
+
90
+ # Get the signed url
91
+ signed_url = prepped.url
92
+
93
+ # Base 64 encode and remove the padding from the end
94
+ signed_url_bytes = signed_url.encode("utf-8")
95
+ base64_bytes = base64.urlsafe_b64encode(signed_url_bytes)
96
+ base64_encoded_signed_url = base64_bytes.decode("utf-8").rstrip("=")
97
+ return base64_encoded_signed_url, __get_expiration_time_ms(request)
98
+
99
+
100
+ def generate_auth_token(region, aws_debug_creds=False):
101
+ """
102
+ Generates an base64-encoded signed url as auth token to authenticate
103
+ with an Amazon MSK cluster using default IAM credentials.
104
+
105
+ Args:
106
+ region (str): The AWS region where the cluster is located.
107
+ Returns:
108
+ str: A base64-encoded authorization token.
109
+ """
110
+
111
+ # Load credentials
112
+ import os
113
+ assert os.environ["AWS_ACCESS_KEY_ID"]
114
+ assert os.environ["AWS_SECRET_ACCESS_KEY"]
115
+
116
+ aws_credentials = Credentials(os.environ["AWS_ACCESS_KEY_ID"],
117
+ os.environ["AWS_SECRET_ACCESS_KEY"])
118
+
119
+ return __construct_auth_token(region, aws_credentials)
@@ -153,6 +153,13 @@ class Client:
153
153
  """
154
154
  return self.web_client.update_topic_partitions(self.subject_openid, topic, new_partitions)
155
155
 
156
+ @requires_login
157
+ def reset_topic(self, topic):
158
+ """
159
+ Deletes and recreates the topic, removing all messages and restoring the topic to the default configurations while user access is not affected.
160
+ """
161
+ return self.web_client.reset_topic(self.subject_openid, topic)
162
+
156
163
  @requires_login
157
164
  def grant_user_access(self, topic, user):
158
165
  """
@@ -167,6 +174,13 @@ class Client:
167
174
  """
168
175
  return self.web_client.grant_user_access(self.subject_openid, topic, user, "revoke")
169
176
 
177
+ @requires_login
178
+ def list_topic_users(self, topic):
179
+ """
180
+ Returns a list of users that have access to the topic.
181
+ """
182
+ return self.web_client.list_topic_users(self.subject_openid, topic)
183
+
170
184
  @requires_login
171
185
  def list_triggers(self):
172
186
  """
@@ -4,20 +4,20 @@ import warnings
4
4
  import time
5
5
 
6
6
  from .client import Client
7
+ from .aws_iam_msk import generate_auth_token
7
8
 
8
9
  # If kafka-python is not installed, Kafka functionality is not available through diaspora-event-sdk.
9
10
  kafka_available = True
10
11
  try:
11
12
  from kafka import KafkaProducer as KProd # type: ignore[import,import-not-found]
12
13
  from kafka import KafkaConsumer as KCons # type: ignore[import,import-not-found]
13
- from aws_msk_iam_sasl_signer import MSKAuthTokenProvider # type: ignore[import,import-not-found]
14
14
  import os
15
15
 
16
16
  class MSKTokenProvider:
17
17
  def token(self):
18
- token, _ = MSKAuthTokenProvider.generate_auth_token("us-east-1")
18
+ token, _ = generate_auth_token("us-east-1")
19
19
  return token
20
- except ImportError:
20
+ except Exception as e:
21
21
  kafka_available = False
22
22
 
23
23
 
@@ -66,6 +66,15 @@ class WebClient(globus_sdk.BaseClient):
66
66
  "NewPartitions": str(new_partitions)}
67
67
  )
68
68
 
69
+ def reset_topic(
70
+ self, subject: UUID_LIKE_T, topic: str
71
+ ) -> globus_sdk.GlobusHTTPResponse:
72
+ return self.post(
73
+ f"/api/v2/topic/{topic}/reset",
74
+ headers={"Subject": str(subject),
75
+ "Topic": topic}
76
+ )
77
+
69
78
  def grant_user_access(
70
79
  self, subject: UUID_LIKE_T, topic: str, user: UUID_LIKE_T, action: str
71
80
  ) -> globus_sdk.GlobusHTTPResponse:
@@ -75,6 +84,15 @@ class WebClient(globus_sdk.BaseClient):
75
84
  "Topic": topic, "User": str(user)}
76
85
  )
77
86
 
87
+ def list_topic_users(
88
+ self, subject: UUID_LIKE_T, topic: str
89
+ ) -> globus_sdk.GlobusHTTPResponse:
90
+ return self.get(
91
+ f"/api/v2/topic/{topic}/users",
92
+ headers={"Subject": str(subject),
93
+ "Topic": topic}
94
+ )
95
+
78
96
  def list_triggers(self, subject: UUID_LIKE_T) -> globus_sdk.GlobusHTTPResponse:
79
97
  return self.get("/api/v2/triggers", headers={"Subject": str(subject)})
80
98
 
@@ -1 +1 @@
1
- __version__ = "0.2.4"
1
+ __version__ = "0.2.6"
@@ -1,16 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: diaspora-event-sdk
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: SDK of Diaspora Event Fabric: Resilience-enabling services for science from HPC to edge
5
5
  Home-page: https://github.com/globus-labs/diaspora-event-sdk
6
- License: LICENSE
6
+ License: Apache 2.0
7
7
  Platform: UNKNOWN
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
10
  Requires-Dist: globus-sdk <4,>=3.20.1
11
11
  Provides-Extra: kafka-python
12
12
  Requires-Dist: kafka-python ; extra == 'kafka-python'
13
- Requires-Dist: aws-msk-iam-sasl-signer-python ; extra == 'kafka-python'
14
13
  Provides-Extra: test
15
14
  Requires-Dist: pytest ; extra == 'test'
16
15
  Requires-Dist: pytest-cov ; extra == 'test'
@@ -19,7 +18,7 @@ Requires-Dist: mypy ; extra == 'test'
19
18
  Requires-Dist: tox ; extra == 'test'
20
19
  Requires-Dist: check-manifest ; extra == 'test'
21
20
 
22
- # Diaspora: Resilience-enabling services for science from HPC to edge
21
+ # Diaspora: Hybrid Event-Driven Architecture for Distributed Scientific Computing
23
22
 
24
23
  ## Event Fabric SDK Installation Guide
25
24
  ### Recommended Method: Use with `kafka-python`
@@ -49,3 +48,4 @@ Note: This method does not include dependencies for `KafkaProducer` and `KafkaCo
49
48
 
50
49
  **Advanced Consumer Functions**: See our [Colab example](https://colab.research.google.com/drive/1tPKfxU2qPsLvNTreF6nKINU62k7pQWxa?usp=sharing) for demonstration.
51
50
 
51
+
@@ -1,11 +1,12 @@
1
1
  diaspora_event_sdk/__init__.py,sha256=v8IN3-WFpliakQKru8TAcmQ4IRdvRe_m9-abSDnGIFM,457
2
- diaspora_event_sdk/version.py,sha256=SBl2EPFW-ltPvQ7vbVWItyAsz3aKYIpjO7vcfr84GkU,22
2
+ diaspora_event_sdk/version.py,sha256=Oz5HbwHMyE87nmwV80AZzpkJPf-wBg7eDuJr_BXZkhU,22
3
3
  diaspora_event_sdk/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  diaspora_event_sdk/sdk/_environments.py,sha256=QyQA7dV4goUKUoxAoaes8OGv0xKxz2qiFBHNGr-vQNA,204
5
- diaspora_event_sdk/sdk/client.py,sha256=Frs1EjG8OJX5kqqPbGOOFN4UE7vUdhBgyEgvA99NpY8,8016
5
+ diaspora_event_sdk/sdk/aws_iam_msk.py,sha256=rT6RipRVt-Zf7pTsMf9UhH2HDNC0FW28LhciVH_45bc,3942
6
+ diaspora_event_sdk/sdk/client.py,sha256=fbjP_YRmGF2eItnMxNkdz5RIRvur0_P8DhE6AlYk4tM,8541
6
7
  diaspora_event_sdk/sdk/decorators.py,sha256=Gel8AyhIjbf4-FNintTNcOqvC9hHH_YwbOH257Nfmf0,884
7
- diaspora_event_sdk/sdk/kafka_client.py,sha256=G1kQQz2TWlahdd2TDdpvaQW7HD7gsuQCnr0tks54ISw,4361
8
- diaspora_event_sdk/sdk/web_client.py,sha256=7dWeKSwB97Hb0O6FvbFMBpp4fKgW-BxprLWb1OiI-ao,4222
8
+ diaspora_event_sdk/sdk/kafka_client.py,sha256=xAxuPmMXIv0i_K_PFqc_BEG3wdGsFdYYvd7gUzeoLV8,4286
9
+ diaspora_event_sdk/sdk/web_client.py,sha256=Rkp0ZUUXCeqbfVFUqX2oxvuLwqqW5_jsJJNN-v2L4FI,4770
9
10
  diaspora_event_sdk/sdk/login_manager/__init__.py,sha256=yeqVgjeHLMX0WZJu2feJmq-fbeXvSxWghVV81ygfY-w,239
10
11
  diaspora_event_sdk/sdk/login_manager/client_login.py,sha256=8ild28_cgPSrLtg3Jhmzpg3EymAvH2UdAhKY52oOB_c,1835
11
12
  diaspora_event_sdk/sdk/login_manager/decorators.py,sha256=EFEp71d0oJ7vo2H8W7DJ2gPrDfGzeNXUNxri1C0l8h0,1047
@@ -18,8 +19,8 @@ diaspora_event_sdk/sdk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
18
19
  diaspora_event_sdk/sdk/utils/uuid_like.py,sha256=xbxf0YXpDhdii16lwPLWRN21qFekHrNrqODSToMPtCg,470
19
20
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
21
  tests/unit/test_client.py,sha256=sJUtPmnNGnohnP38RQrwcJ4D5j3-g1WFQ6gaKf520AQ,3019
21
- diaspora_event_sdk-0.2.4.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
22
- diaspora_event_sdk-0.2.4.dist-info/METADATA,sha256=GT3z-Ql24vHUPgbjWlVxPvp0OioEJlgADsiWXYsMo3A,2505
23
- diaspora_event_sdk-0.2.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
24
- diaspora_event_sdk-0.2.4.dist-info/top_level.txt,sha256=OVun-67t3fkLFEIwvJuNINgFFvAc--bClYhXjLhMmvs,25
25
- diaspora_event_sdk-0.2.4.dist-info/RECORD,,
22
+ diaspora_event_sdk-0.2.6.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
23
+ diaspora_event_sdk-0.2.6.dist-info/METADATA,sha256=2JJCyb4-F55L3mHG25HfgESP4OEgpTWuEs-UsRUxoOQ,2449
24
+ diaspora_event_sdk-0.2.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
25
+ diaspora_event_sdk-0.2.6.dist-info/top_level.txt,sha256=OVun-67t3fkLFEIwvJuNINgFFvAc--bClYhXjLhMmvs,25
26
+ diaspora_event_sdk-0.2.6.dist-info/RECORD,,