Skip to content

Commit 9aaa262

Browse files
author
Andrew Ghafari
committed
allowing lazy loaded arguments as arguments
1 parent acc6c95 commit 9aaa262

File tree

4 files changed

+86
-12
lines changed

4 files changed

+86
-12
lines changed

nodestream/pipeline/extractors/credential_utils.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
11
from datetime import datetime
22
from time import time
3-
from typing import Optional
3+
from typing import Optional, Union
44
from uuid import uuid4
55

66
import boto3
77
import pytz
88
from botocore.credentials import RefreshableCredentials
99
from botocore.session import Session
10+
from nodestream.file_io import LazyLoadedArgument
1011

1112

1213
class AwsClientFactory:
1314
def __init__(
1415
self,
15-
assume_role_arn: Optional[str] = None,
16-
assume_role_external_id: Optional[str] = None,
16+
assume_role_arn: Optional[Union[LazyLoadedArgument,str]] = None,
17+
assume_role_external_id: Optional[Union[LazyLoadedArgument,str]] = None,
1718
session_ttl: int = 3000,
1819
**boto_session_args
1920
) -> None:
20-
self.assume_role_arn = assume_role_arn
21-
self.assume_role_external_id = assume_role_external_id
21+
if isinstance(assume_role_arn, LazyLoadedArgument):
22+
self.assume_role_arn = assume_role_arn.get_value()
23+
else:
24+
self.assume_role_arn = assume_role_arn
25+
if isinstance(assume_role_external_id, LazyLoadedArgument):
26+
self.assume_role_external_id = assume_role_external_id.get_value()
27+
else:
28+
self.assume_role_external_id = assume_role_external_id
29+
2230
self.session_args = self._init_session_args(**boto_session_args)
2331
self.session_ttl = session_ttl
2432

nodestream/project/storage.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from dataclasses import dataclass, field
2-
from typing import Any, Dict, Optional
3-
2+
from typing import Any, Dict, Optional, Union
3+
from nodestream.file_io import LazyLoadedArgument
44
from ..pipeline.object_storage import ObjectStore, Signer
55

66

@@ -9,14 +9,17 @@ class StoreConfiguration:
99
name: str
1010
storage_type: str
1111
arguments: Dict[str, Any]
12-
hmac_key: Optional[any] = None
12+
hmac_key: Optional[Union[LazyLoadedArgument,str]] = None
1313

1414
def initialize(self) -> ObjectStore:
1515
store = ObjectStore.from_file_arguments(self.storage_type, **self.arguments)
1616
if self.hmac_key:
17-
return store.signed(Signer.hmac(self.hmac_key))
18-
else:
19-
return store
17+
if isinstance(self.hmac_key, LazyLoadedArgument):
18+
resolved_key = self.hmac_key.get_value()
19+
return store.signed(Signer.hmac(resolved_key))
20+
else:
21+
return store.signed(Signer.hmac(self.hmac_key))
22+
return store
2023

2124
def to_file_data(self):
2225
return dict(
@@ -40,7 +43,7 @@ def describe_yaml_schema():
4043
from schema import Optional, Schema
4144

4245
return Schema(
43-
{"name": str, "type": str, Optional("hmac_key"): str, Optional(str): object}
46+
{"name": str, "type": str, Optional("hmac_key"): LazyLoadedArgument, Optional(str): object}
4447
)
4548

4649

tests/unit/pipeline/extractors/stores/aws/test_credential_utils.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
from freezegun import freeze_time
77
from hamcrest import assert_that, equal_to, has_key, not_
88

9+
from nodestream.file_io import LazyLoadedArgument
10+
from unittest.mock import Mock
11+
912

1013
@pytest.fixture
1114
def client_with_role():
@@ -145,3 +148,37 @@ def test_make_client(mocker, client_without_role):
145148
return_value=session
146149
)
147150
client_without_role.make_client("s3")
151+
152+
def create_mock_lazy_loaded_argument(value):
153+
mock = Mock(spec=LazyLoadedArgument)
154+
mock.get_value.return_value = value
155+
return mock
156+
157+
def test_init_with_lazy_loaded_role_arn():
158+
from nodestream.pipeline.extractors.credential_utils import AwsClientFactory
159+
160+
lazy_role_arn = create_mock_lazy_loaded_argument("arn:aws:iam::123456789012:role/test")
161+
client = AwsClientFactory(assume_role_arn=lazy_role_arn)
162+
163+
assert_that(client.assume_role_arn, equal_to("arn:aws:iam::123456789012:role/test"))
164+
165+
def test_init_with_lazy_loaded_external_id():
166+
from nodestream.pipeline.extractors.credential_utils import AwsClientFactory
167+
168+
lazy_external_id = create_mock_lazy_loaded_argument("test-external-id")
169+
client = AwsClientFactory(assume_role_external_id=lazy_external_id)
170+
171+
assert_that(client.assume_role_external_id, equal_to("test-external-id"))
172+
173+
def test_init_with_both_lazy_loaded_arguments():
174+
from nodestream.pipeline.extractors.credential_utils import AwsClientFactory
175+
176+
lazy_role_arn = create_mock_lazy_loaded_argument("arn:aws:iam::123456789012:role/test")
177+
lazy_external_id = create_mock_lazy_loaded_argument("test-external-id")
178+
client = AwsClientFactory(
179+
assume_role_arn=lazy_role_arn,
180+
assume_role_external_id=lazy_external_id
181+
)
182+
183+
assert_that(client.assume_role_arn, equal_to("arn:aws:iam::123456789012:role/test"))
184+
assert_that(client.assume_role_external_id, equal_to("test-external-id"))

tests/unit/project/test_storage.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import base64
2+
13
import pytest
24
from hamcrest import assert_that, contains, equal_to, instance_of
35

@@ -7,6 +9,10 @@
79
SignedObjectStore,
810
)
911
from nodestream.project.storage import StorageConfiguration, StoreConfiguration
12+
from unittest.mock import Mock
13+
from hamcrest import assert_that, instance_of
14+
from nodestream.file_io import LazyLoadedArgument
15+
from nodestream.pipeline.object_storage import SignedObjectStore, DirectoryObjectStore
1016

1117

1218
@pytest.fixture
@@ -88,3 +94,23 @@ def test_storage_configuration_to_file_data(store_config):
8894
file_data = storage_config.to_file_data()
8995
expected_data = {"stores": [("test_store", store_config)]}
9096
assert_that(file_data, equal_to(expected_data))
97+
98+
99+
def test_store_configuration_initialize_with_lazy_hmac(tmp_path):
100+
expected_hmac = "dvHdCrVbRPp1HcmWX78Ryw=="
101+
mock_lazy_hmac = Mock(spec=LazyLoadedArgument)
102+
mock_lazy_hmac.get_value.return_value = expected_hmac
103+
104+
store_config = StoreConfiguration(
105+
name="test-store",
106+
storage_type="local",
107+
arguments={"root": tmp_path},
108+
hmac_key=mock_lazy_hmac
109+
)
110+
111+
store = store_config.initialize()
112+
assert_that(
113+
base64.b64encode(store.signer.key).decode(),
114+
equal_to(expected_hmac)
115+
)
116+
mock_lazy_hmac.get_value.assert_called_once()

0 commit comments

Comments
 (0)