-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Fix/aml 509849 #6120
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
Open
lucasjia-aws
wants to merge
3
commits into
aws:master
Choose a base branch
from
lucasjia-aws:fix/AML-509849
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Fix/aml 509849 #6120
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
231bae6
fix(sagemaker-core): remove dev-only endpoint override and fix client…
lucasjia-aws ad7a9c4
fix(sagemaker-train): mask credential-shaped values in container env …
lucasjia-aws 18d1e7a
fix(sagemaker-core): address review feedback on client singleton
lucasjia-aws File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -318,6 +318,9 @@ def __bool__(self): | |
| class SingletonMeta(type): | ||
|
Collaborator
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. Singleton pinning — SageMakerClient is a process-wide singleton keyed by class only, so the first instance's session/region/endpoint is pinned for all later calls. I believe this is by design. We don't need to fix it. |
||
| """ | ||
| Singleton metaclass. Ensures that a single instance of a class using this metaclass is created. | ||
|
|
||
| A class may define a ``_singleton_key(*args, **kwargs)`` classmethod returning | ||
| a hashable key to cache instances per ``(class, key)`` instead of per class. | ||
| """ | ||
|
|
||
| _instances = {} | ||
|
|
@@ -327,21 +330,42 @@ def __call__(cls, *args, **kwargs): | |
| Overrides the call method to return an existing instance of the class if it exists, | ||
| or create a new one if it doesn't. | ||
| """ | ||
| if cls not in cls._instances: | ||
| key = cls | ||
| key_fn = getattr(cls, "_singleton_key", None) | ||
| if key_fn is not None: | ||
| key = (cls, key_fn(*args, **kwargs)) | ||
| if key not in cls._instances: | ||
| instance = super().__call__(*args, **kwargs) | ||
| cls._instances[cls] = instance | ||
| return cls._instances[cls] | ||
| cls._instances[key] = instance | ||
| return cls._instances[key] | ||
|
|
||
|
|
||
| class SageMakerClient(metaclass=SingletonMeta): | ||
| """ | ||
| A singleton class for creating a SageMaker client. | ||
| """ | ||
|
|
||
| @staticmethod | ||
| def _singleton_key(session: Session = None, region_name: str = None, *args, **kwargs): | ||
| """Cache instances per (session, region). | ||
|
|
||
| id(session) is stable because the cached instance holds a reference to | ||
| the session, so the object cannot be garbage-collected while the entry | ||
| lives. | ||
| """ | ||
| session_key = id(session) if session is not None else None | ||
| return (session_key, region_name) | ||
|
|
||
| @classmethod | ||
| def reset(cls): | ||
| """Reset the singleton instance so the next call re-reads env vars.""" | ||
| SingletonMeta._instances.pop(cls, None) | ||
| """Reset cached singleton instances for this class.""" | ||
| keys = [ | ||
| k | ||
| for k in SingletonMeta._instances | ||
| if k == cls or (isinstance(k, tuple) and k[0] is cls) | ||
| ] | ||
| for key in keys: | ||
| SingletonMeta._instances.pop(key, None) | ||
|
|
||
| def __init__( | ||
| self, | ||
|
|
@@ -368,53 +392,12 @@ def __init__( | |
| self.config = Config(user_agent_extra=get_user_agent_extra_suffix()) | ||
| self.session = session | ||
| self.region_name = region_name | ||
| # Read region from environment variable, default to us-west-2 | ||
| import os | ||
| env_region = os.environ.get('SAGEMAKER_REGION', region_name) | ||
| env_stage = os.environ.get('SAGEMAKER_STAGE', 'prod') # default to gamma | ||
| logger.info(f"Runs on sagemaker {env_stage}, region:{env_region}") | ||
|
|
||
| endpoint_url = os.environ.get('SAGEMAKER_ENDPOINT') | ||
| runtime_endpoint_url = os.environ.get('SAGEMAKER_RUNTIME_ENDPOINT') | ||
|
|
||
| # TODO: Remove post-launch. This loads a custom botocore service model | ||
| # (from the 'sample/' directory) that includes pre-GA Job APIs | ||
| # (CreateJob, DescribeJob, ListJobs, etc.) not yet in the public | ||
| # botocore release. Once these APIs ship in the official botocore | ||
| # service-2.json, this custom loader is unnecessary and the standard | ||
| # session.client("sagemaker", endpoint_url=...) path will work. | ||
| # | ||
| # NOTE: The custom data loader is registered on the caller-provided | ||
| # session's underlying botocore session so that the "sagemaker" | ||
| # control-plane client keeps the caller's credentials/profile. Using a | ||
| # fresh botocore.session.get_session() here would silently fall back to | ||
| # the default AWS profile and break cross-account calls (issue #6069). | ||
| import botocore.loaders | ||
| import pathlib | ||
|
|
||
| # Look for bundled service model inside the package first, | ||
| # fall back to source-tree layout (sample/ as sibling of src/) | ||
| _bundled = pathlib.Path(__file__).resolve().parent.parent / "data" / "sample" | ||
| _source_tree = pathlib.Path(__file__).resolve().parent.parent.parent.parent.parent / "sample" | ||
| sample_model_dir = str(_bundled if _bundled.exists() else _source_tree) | ||
| loader = botocore.loaders.Loader( | ||
| extra_search_paths=[sample_model_dir], | ||
| include_default_search_paths=True, | ||
| ) | ||
| # boto3.Session exposes its underlying botocore session as `_session`. | ||
| session._session.register_component('data_loader', loader) | ||
|
|
||
| self.sagemaker_client = session.client( | ||
| "sagemaker", | ||
| region_name=env_region, | ||
| endpoint_url=endpoint_url, | ||
| config=self.config, | ||
| "sagemaker", region_name, config=self.config | ||
| ) | ||
|
|
||
| self.sagemaker_runtime_client = session.client( | ||
| "sagemaker-runtime", region_name, | ||
| endpoint_url=runtime_endpoint_url, | ||
| config=self.config, | ||
| "sagemaker-runtime", region_name, config=self.config | ||
| ) | ||
| self.sagemaker_featurestore_runtime_client = session.client( | ||
| "sagemaker-featurestore-runtime", region_name, config=self.config | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Env-log masking gap — the container-driver startup logger masks by key name only, so a credential-shaped value under an innocuous key name would be logged in clear text.
The PR is doing regex against some known patterns, but credentials may/may not match that regex.
I wonder what's the best practice to filter out credentials from logs. I would suggest to explore if there any official AWS guidance on this.