Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 1.3k
feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support#5816
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
Uh oh!
There was an error while loading. Please reload this page.
feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support #5816
Changes from all commits
ac5f7b718cd3191aa4b3d87960038d8847f544fd94932c9976d7e7bf5eca24b6a9e051eb1eaf82df34bb6f08b0650c87f008a884ff8479c5609c0e671de6cca4b6fa59c2c22d0f0b1905b4914c589ae0af3e3efadc663688436677caa8650052d4ab84cefdd11dd57e84ebd2d97051618f79fe7d923bd4File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -15,6 +15,8 @@ | ||
| from typing import Callable, Dict, Optional, Tuple, List, Union | ||
| import attr | ||
| from cryptography.hazmat.primitives.asymmetric import ec | ||
| from cryptography.hazmat.primitives import serialization as crypto_serialization | ||
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. Is this intro of a library needed? If so, I see that CollaboratorAuthor 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. They are needed yes. | ||
| from sagemaker.core.helper.session_helper import Session | ||
| from sagemaker.mlops.feature_store.feature_processor._constants import ( | ||
| @@ -52,13 +54,13 @@ class ConfigUploader: | ||
| def prepare_step_input_channel_for_spark_mode( | ||
| self, func: Callable, s3_base_uri: str, sagemaker_session: Session | ||
| ) -> Tuple[List[Channel], Dict]: | ||
| ) -> Tuple[List[Channel], Dict, str]: | ||
| """Prepares input channels for SageMaker Pipeline Step. | ||
| Returns: | ||
| Tuple of (List[Channel], spark_dependency_paths dict) | ||
| Tuple of (List[Channel], spark_dependency_paths dict, public_key_pem str) | ||
| """ | ||
| self._prepare_and_upload_callable(func, s3_base_uri, sagemaker_session) | ||
| public_key_pem = self._prepare_and_upload_callable(func, s3_base_uri, sagemaker_session) | ||
| bootstrap_scripts_s3uri = self._prepare_and_upload_runtime_scripts( | ||
| self.remote_decorator_config.spark_config, | ||
| s3_base_uri, | ||
| @@ -139,18 +141,33 @@ def prepare_step_input_channel_for_spark_mode( | ||
| SPARK_JAR_FILES_PATH: submit_jars_s3_paths, | ||
| SPARK_PY_FILES_PATH: submit_py_files_s3_paths, | ||
| SPARK_FILES_PATH: submit_files_s3_path, | ||
| } | ||
| }, public_key_pem | ||
| def _prepare_and_upload_callable( | ||
| self, func: Callable, s3_base_uri: str, sagemaker_session: Session | ||
| ) -> None: | ||
| """Prepares and uploads callable to S3""" | ||
| ) -> str: | ||
| """Prepares and uploads callable to S3. | ||
| Returns: | ||
| str: The public key PEM string for signature verification on the remote side. | ||
| """ | ||
| private_key = ec.generate_private_key(ec.SECP256R1()) | ||
| public_key_pem = ( | ||
| private_key.public_key() | ||
| .public_bytes( | ||
| crypto_serialization.Encoding.PEM, | ||
| crypto_serialization.PublicFormat.SubjectPublicKeyInfo, | ||
| ) | ||
| .decode("utf-8") | ||
| ) | ||
| stored_function = StoredFunction( | ||
| sagemaker_session=sagemaker_session, | ||
| s3_base_uri=s3_base_uri, | ||
| signing_key=private_key, | ||
| s3_kms_key=self.remote_decorator_config.s3_kms_key, | ||
| ) | ||
| stored_function.save(func) | ||
| return public_key_pem | ||
| def _prepare_and_upload_workspace( | ||
| self, | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"). You | ||
| # may not use this file except in compliance with the License. A copy of | ||
| # the License is located at | ||
| # | ||
| # http://aws.amazon.com/apache2.0/ | ||
| # | ||
| # or in the "license" file accompanying this file. This file is | ||
| # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF | ||
| # ANY KIND, either express or implied. See the License for the specific | ||
| # language governing permissions and limitations under the License. | ||
| """Resolves SageMaker Spark container image URIs based on installed PySpark and Python versions.""" | ||
| from __future__ import absolute_import | ||
| import sys | ||
| from sagemaker.core import image_uris | ||
| SPARK_IMAGE_SUPPORT_MATRIX = { | ||
| "3.1": ["py37"], | ||
| "3.2": ["py39"], | ||
| "3.3": ["py39"], | ||
| "3.5": ["py39", "py312"], | ||
| } | ||
| def _get_spark_image_uri(session): | ||
| """Resolve the SageMaker Spark container image URI for the installed PySpark and Python versions. | ||
| Args: | ||
| session: SageMaker Session with boto_region_name attribute. | ||
| Returns: | ||
| str: The ECR image URI for the matching Spark container. | ||
| Raises: | ||
| ValueError: If the Spark/Python version combination is not supported. | ||
| """ | ||
| import pyspark | ||
| spark_version = ".".join(pyspark.__version__.split(".")[:2]) | ||
| py_version = f"py{sys.version_info[0]}{sys.version_info[1]}" | ||
| supported_py = SPARK_IMAGE_SUPPORT_MATRIX.get(spark_version) | ||
| if supported_py is None: | ||
| supported = ", ".join(sorted(SPARK_IMAGE_SUPPORT_MATRIX.keys())) | ||
| raise ValueError( | ||
| f"No SageMaker Spark container image available for Spark {spark_version}. " | ||
| f"Supported versions for remote execution: {supported}." | ||
| ) | ||
| if py_version not in supported_py: | ||
| raise ValueError( | ||
| f"SageMaker Spark {spark_version} container images support " | ||
| f"{', '.join(supported_py)}. Current Python version: {py_version}." | ||
| ) | ||
| return image_uris.retrieve( | ||
| framework="spark", | ||
| region=session.boto_region_name, | ||
| version=spark_version, | ||
| py_version=py_version, | ||
| container_version="v1", | ||
| ) |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pyspark is not installed where this command runs so we read the $SPARK_HOME/usr/lib/spark/RELEASE file which has the currently installed spark version