Repository navigation
feat(transformations): Added rotate keys api endpoint support in sdk #2921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
db32b6a
84dc9a5
dec9e14
f95abdc
f5330de
f933c76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,9 @@ | |
| ExternalDataSource, | ||
| ExternalDataSourceFormat, | ||
| ExternalDataSourceList, | ||
| ExternalDataSourceRotatedKeys, | ||
| ExternalDataSourceRotatedKeysList, | ||
| ExternalDataSourceRotateKeys, | ||
| ExternalDataSourceUsability, | ||
| ExternalDataSourceWrite, | ||
| ) | ||
|
|
@@ -23,6 +26,7 @@ | |
|
|
||
| class TransformationExternalDataSourcesAPI(APIClient): | ||
| _RESOURCE_PATH = "/transformations/externaldata" | ||
| _ROTATE_KEYS_LIMIT = 10 | ||
|
|
||
| def __init__(self, config: ClientConfig, api_version: str | None, cognite_client: AsyncCogniteClient) -> None: | ||
| super().__init__(config, api_version, cognite_client) | ||
|
|
@@ -34,6 +38,11 @@ def __init__(self, config: ClientConfig, api_version: str | None, cognite_client | |
| sdk_maturity="alpha", | ||
| feature_name="Retrieving Transformation External Data Sources by external ID", | ||
| ) | ||
| self._rotate_keys_warning = FeaturePreviewWarning( | ||
| api_maturity="alpha", | ||
| sdk_maturity="alpha", | ||
| feature_name="Rotating keys of Transformation External Data Sources", | ||
| ) | ||
| self._RETRIEVE_LIMIT = 100 # ExternalDataSource.ByIds.maxItemsPerRequest | ||
|
|
||
| @overload | ||
|
|
@@ -286,6 +295,66 @@ async def delete(self, external_id: str | SequenceNotStr[str]) -> None: | |
| wrap_ids=True, | ||
| ) | ||
|
|
||
| @overload | ||
| async def rotate_keys(self, rotation: ExternalDataSourceRotateKeys) -> ExternalDataSourceRotatedKeys: ... | ||
|
|
||
| @overload | ||
| async def rotate_keys( | ||
| self, rotation: Sequence[ExternalDataSourceRotateKeys] | ||
| ) -> ExternalDataSourceRotatedKeysList: ... | ||
|
|
||
| async def rotate_keys( | ||
| self, rotation: ExternalDataSourceRotateKeys | Sequence[ExternalDataSourceRotateKeys] | ||
| ) -> ExternalDataSourceRotatedKeys | ExternalDataSourceRotatedKeysList: | ||
| """`Rotate the keys of Snowflake external data sources <https://api-docs.cognite.com/20230101-alpha/tag/Transformation-External-Data-Sources/operation/rotateExternalDataSourceKeys>`_. | ||
|
|
||
| The server generates a new key pair for each data source and returns the new public key, which you must | ||
| register with the Snowflake user. Only Snowflake data sources support this. The operation is atomic: if any | ||
| item fails, no keys are rotated. At most 10 data sources can be rotated per call, with unique external IDs. | ||
|
|
||
| Args: | ||
| rotation (ExternalDataSourceRotateKeys | Sequence[ExternalDataSourceRotateKeys]): The rotation(s) to perform. Each ``expiry_time`` must be in the future and at most one year from now. | ||
|
|
||
| Returns: | ||
| ExternalDataSourceRotatedKeys | ExternalDataSourceRotatedKeysList: The new public key and expiry time of each rotated data source. | ||
|
|
||
| Raises: | ||
| ValueError: If more than 10 rotations are passed. | ||
|
|
||
| Examples: | ||
|
|
||
| Rotate the keys of a Snowflake data source, valid for 30 days: | ||
|
|
||
| >>> from cognite.client import CogniteClient, AsyncCogniteClient | ||
| >>> from cognite.client.data_classes.transformations.externaldata import ( | ||
| ... ExternalDataSourceRotateKeys, | ||
| ... ) | ||
| >>> from cognite.client.utils._time import timestamp_to_ms | ||
| >>> client = CogniteClient() | ||
| >>> # async_client = AsyncCogniteClient() # another option | ||
| >>> expiry_time = timestamp_to_ms("30d-ahead") | ||
| >>> res = client.transformations.external_data_sources.rotate_keys( | ||
| ... ExternalDataSourceRotateKeys("snowflake-analytics-prod", expiry_time) | ||
| ... ) | ||
| >>> new_public_key = res.public_key | ||
| """ | ||
| self._rotate_keys_warning.warn() | ||
| items = [rotation] if isinstance(rotation, ExternalDataSourceRotateKeys) else list(rotation) | ||
| if not items: | ||
| return ExternalDataSourceRotatedKeysList([]) | ||
| if len(items) > self._ROTATE_KEYS_LIMIT: | ||
| raise ValueError( | ||
| f"At most {self._ROTATE_KEYS_LIMIT} data sources can be rotated per call (the operation is atomic " | ||
| f"and cannot be split), got {len(items)}" | ||
| ) | ||
| res = await self._post( | ||
| url_path=self._RESOURCE_PATH + "/rotatekeys", | ||
| json={"items": [item.dump(camel_case=True) for item in items]}, | ||
| semaphore=self._get_semaphore("write"), | ||
| ) | ||
| rotated = ExternalDataSourceRotatedKeysList._load(res.json()["items"]) | ||
| return rotated[0] if isinstance(rotation, ExternalDataSourceRotateKeys) else rotated | ||
|
Comment on lines
+342
to
+356
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current implementation of To align with the SDK's established patterns and improve robustness, we should support both is_single = isinstance(rotation, (ExternalDataSourceRotateKeys, dict))
items = [rotation] if is_single else list(rotation)
if not items:
return ExternalDataSourceRotatedKeysList([])
if len(items) > self._ROTATE_KEYS_LIMIT:
raise ValueError(
f"At most {self._ROTATE_KEYS_LIMIT} data sources can be rotated per call (the operation is atomic "
f"and cannot be split), got {len(items)}"
)
processed_items: list[ExternalDataSourceRotateKeys] = []
for item in items:
if isinstance(item, dict):
processed_items.append(ExternalDataSourceRotateKeys.load(item))
elif isinstance(item, ExternalDataSourceRotateKeys):
processed_items.append(item)
else:
raise TypeError(f"Expected ExternalDataSourceRotateKeys or dict, got {type(item)}")
self._rotate_keys_warning.warn()
res = await self._post(
url_path=self._RESOURCE_PATH + "/rotatekeys",
json={"items": [item.dump(camel_case=True) for item in processed_items]},
semaphore=self._get_semaphore("write"),
)
rotated = ExternalDataSourceRotatedKeysList._load(res.json()["items"])
return rotated[0] if is_single else rotated
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not true. Create and retrieve doesn't support dict or list of dicts. Will leave for reviewer in case they think otherwise |
||
|
|
||
| async def verify_usability(self, external_id: str) -> ExternalDataSourceUsability: | ||
| """`Verify external data source usability <https://api-docs.cognite.com/20230101-beta/tag/Transformation-External-Data-Sources/operation/verifyExternalDataSourceUsability>`_. | ||
|
|
||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.