Skip to content
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

Fix for keyring errors when initializing Flyte for_sandbox config client #2962

Open
wants to merge 39 commits into
base: master
Choose a base branch
from

Conversation

taieeuu
Copy link
Contributor

@taieeuu taieeuu commented Nov 27, 2024

Fix for keyring errors when initializing Flyte for_sandbox config client (needs verification)

Tracking issue

flyteorg/flyte#4354

What changes were proposed in this pull request?

First, I started by analyzing the issue reporter's code and modified the Config.for_sandbox() method to add a new value AuthType.No_Auth to auth_mode. Additionally, I updated the AuthUnaryInterceptor class to handle gRPC responses. If a 401 error (i.e., grpc.StatusCode.UNAUTHENTICATED) is encountered, it will trigger the creation of a PKCE authenticator.

How was this patch tested?

I am having difficulty replicating the issue reporter's environment, as it seems to require a public domain setup and GNOME keyring installed. However, I followed the suggestions from the discussion forum and implemented this fix.

Check all the applicable boxes

  • I updated the documentation accordingly.
  • All new and existing tests passed.
  • All commits are signed-off.

Summary by Bito

Implementation of keyring error handling for Flyte sandbox config client, featuring gRPC health checking and improved authentication flow. Restructured grpc health module imports by moving health_pb2 and health_pb2_grpc imports from global scope to client method level. The solution introduces service availability verification before authentication attempts and includes exception handling for gRPC status codes, with a fallback mechanism from unauthenticated to authenticated channels.

Unit tests added: False

Estimated effort to review (1-5, lower is better): 2

Copy link

welcome bot commented Nov 27, 2024

Thank you for opening this pull request! 🙌

These tips will help get your PR across the finish line:

  • Most of the repos have a PR template; if not, fill it out to the best of your knowledge.
  • Sign off your commits (Reference: DCO Guide).

Comment on lines 70 to 71
if e.code() == grpc.StatusCode.UNAUTHENTICATED or e.code() == grpc.StatusCode.UNKNOWN:
self._authenticator.refresh_credentials()
updated_call_details = self._call_details_with_auth_metadata(client_call_details)
return continuation(updated_call_details, request)
return self._handle_unauthenticated_error(fut, client_call_details, request)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add comments about response 401...

Copy link
Member

@Future-Outlier Future-Outlier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this log provided by @Tom-Newton can help.

tomnewton@ben-nevis:~/WayveCode/wayve/ai/nvs/services/workflow$ python /home/tomnewton/Documents/reproduce_key_vault_error.py
/usr/lib/python3/dist-packages/paramiko/transport.py:219: CryptographyDeprecationWarning: Blowfish has been deprecated
"class": algorithms.Blowfish,
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ /home/tomnewton/Documents/reproduce_key_vault_error.py:6 in <module>                                                                                                                                                                                       │
│                                                                                                                                                                                                                                                            │
│ ❱ 6 remote.client                                                                                                                                                                                                                                          │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/flytekit/remote/remote.py:205 in client                                                                                                                                                                 │
│                                                                                                                                                                                                                                                            │
│ ❱  205 │   │   │   self._client = SynchronousFlyteClient(self.config.platform, **self._kwargs)                                                                                                                                                             │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/flytekit/clients/raw.py:44 in __init__                                                                                                                                                                  │
│                                                                                                                                                                                                                                                            │
│ ❱  44 │   │   self._channel = wrap_exceptions_channel(cfg, upgrade_channel_to_authenticated(cf                                                                                                                                                             │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/flytekit/clients/auth_helper.py:111 in upgrade_channel_to_authenticated                                                                                                                                 │
│                                                                                                                                                                                                                                                            │
│ ❱ 111authenticator = get_authenticator(cfg, RemoteClientConfigStore(in_channel))                                                                                                                                                                      │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/flytekit/clients/auth_helper.py:69 in get_authenticator                                                                                                                                                 │
│                                                                                                                                                                                                                                                            │
│ ❱  69 │   │   return PKCEAuthenticator(cfg.endpoint, cfg_store, verify=verify)                                                                                                                                                                             │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/flytekit/clients/auth/authenticator.py:102 in __init__                                                                                                                                                  │
│                                                                                                                                                                                                                                                            │
│ ❱ 102 │   │   super().__init__(endpoint, header_key, KeyringStore.retrieve(endpoint), verify=v                                                                                                                                                             │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/flytekit/clients/auth/keyring.py:49 in retrieve                                                                                                                                                         │
│                                                                                                                                                                                                                                                            │
│ ❱ 49 │   │   │   refresh_token = _keyring.get_password(for_endpoint, KeyringStore._refresh_to                                                                                                                                                              │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/keyring/core.py:55 in get_password                                                                                                                                                                      │
│                                                                                                                                                                                                                                                            │
│ ❱  55return get_keyring().get_password(service_name, username)                                                                                                                                                                                        │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/keyring/backends/chainer.py:49 in get_password                                                                                                                                                          │
│                                                                                                                                                                                                                                                            │
│ ❱ 49 │   │   │   password = keyring.get_password(service, username)                                                                                                                                                                                        │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/keyring/backends/SecretService.py:78 in get_password                                                                                                                                                    │
│                                                                                                                                                                                                                                                            │
│ ❱  78 │   │   collection = self.get_preferred_collection()                                                                                                                                                                                                 │
│                                                                                                                                                                                                                                                            │
│ /home/tomnewton/.local/lib/python3.8/site-packages/keyring/backends/SecretService.py:67 in get_preferred_collection                                                                                                                                        │
│                                                                                                                                                                                                                                                            │
│ ❱  67 │   │   │   │   raise KeyringLocked("Failed to unlock the collection!")                                                                                                                                                                              │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
KeyringLocked: Failed to unlock the collection!

@Tom-Newton
Copy link
Contributor

I just tested a couple of scenarios where I previously had problems and it seems to be working now. Thanks for working on this 🙌.

Signed-off-by: taieeuu <[email protected]>
@taieeuu taieeuu changed the title Fix for keyring errors when initializing Flyte for_sandbox config client (needs verification) Fix for keyring errors when initializing Flyte for_sandbox config client Dec 5, 2024
Comment on lines 93 to 102
try:
if isinstance(self._authenticator, Authenticator) and not isinstance(
self._authenticator, PKCEAuthenticator
):
logging.info("Current authenticator is 'None', switching to PKCEAuthenticator")

from flytekit.clients.auth.authenticator import PKCEAuthenticator
from flytekit.clients.auth_helper import get_session

session = get_session(self._cfg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we move import under try: ...?
why this work for Newton?
this shouldn't work.

@Future-Outlier Future-Outlier self-assigned this Dec 9, 2024
Copy link

codecov bot commented Dec 23, 2024

Codecov Report

Attention: Patch coverage is 25.00000% with 21 lines in your changes missing coverage. Please review.

Project coverage is 76.14%. Comparing base (9b94910) to head (3d142c3).
Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
flytekit/clients/raw.py 25.00% 20 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master    #2962       +/-   ##
===========================================
+ Coverage   47.02%   76.14%   +29.12%     
===========================================
  Files         201      201               
  Lines       21203    21301       +98     
  Branches     2732     2740        +8     
===========================================
+ Hits         9970    16220     +6250     
+ Misses      10744     4279     -6465     
- Partials      489      802      +313     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
@flyte-bot
Copy link
Contributor

flyte-bot commented Dec 28, 2024

Code Review Agent Run #00ff28

Actionable Suggestions - 1
  • flytekit/clients/raw.py - 1
Additional Suggestions - 2
  • dev-requirements.in - 1
    • Consider consolidating gRPC dependency declarations · Line 64-66
  • flytekit/clients/raw.py - 1
    • Consider explicit health check returns · Line 89-92
Review Details
  • Files reviewed - 5 · Commit Range: 21ebec7..569558e
    • dev-requirements.in
    • dev-requirements.txt
    • flytekit/clients/raw.py
    • tests/flytekit/unit/clients/test_friendly.py
    • tests/flytekit/unit/clients/test_raw.py
  • Files skipped - 2
    • .github/workflows/monodocs_build.yml - Reason: Filter setting
    • .github/workflows/pythonbuild.yml - Reason: Filter setting
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

AI Code Review powered by Bito Logo

@flyte-bot
Copy link
Contributor

flyte-bot commented Dec 28, 2024

Changelist by Bito

This pull request implements the following key changes.

Key Change Files Impacted
Feature Improvement - Enhanced gRPC Authentication and Health Checking

raw.py - Added gRPC health checking and improved authentication flow with exception handling

dev-requirements.in - Added gRPC dependencies for health checking functionality

dev-requirements.txt - Updated dependencies with grpcio-health-checking package

Testing - Updated Test Cases for Authentication Flow

test_friendly.py - Added health check mocking to authentication tests

test_raw.py - Updated test cases with gRPC health check mocks

Comment on lines +62 to +72
base_channel = get_channel(cfg, options=options)

if self.check_grpc_health_with_authentication(base_channel):
self._channel = wrap_exceptions_channel(cfg, base_channel)
else:
self._channel = wrap_exceptions_channel(
cfg,
upgrade_channel_to_authenticated(
cfg, upgrade_channel_to_proxy_authenticated(cfg, get_channel(cfg, options=options))
),
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider caching channel creation

Consider caching the base_channel creation to avoid redundant channel creation. Currently, get_channel() is called twice when authentication fails.

Code suggestion
Check the AI-generated fix before applying
Suggested change
base_channel = get_channel(cfg, options=options)
if self.check_grpc_health_with_authentication(base_channel):
self._channel = wrap_exceptions_channel(cfg, base_channel)
else:
self._channel = wrap_exceptions_channel(
cfg,
upgrade_channel_to_authenticated(
cfg, upgrade_channel_to_proxy_authenticated(cfg, get_channel(cfg, options=options))
),
)
base_channel = get_channel(cfg, options=options)
if self.check_grpc_health_with_authentication(base_channel):
self._channel = wrap_exceptions_channel(cfg, base_channel)
else:
self._channel = wrap_exceptions_channel(
cfg,
upgrade_channel_to_authenticated(
cfg, upgrade_channel_to_proxy_authenticated(cfg, base_channel)
),
)

Code Review Run #00ff28


Is this a valid issue, or was it incorrectly flagged by the Agent?

  • it was incorrectly flagged

Signed-off-by: taieeuu <[email protected]>
Signed-off-by: taieeuu <[email protected]>
@flyte-bot
Copy link
Contributor

flyte-bot commented Dec 28, 2024

Code Review Agent Run #10536f

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 569558e..3d142c3
    • flytekit/clients/raw.py
  • Files skipped - 1
    • .github/workflows/pythonbuild.yml - Reason: Filter setting
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

AI Code Review powered by Bito Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In review
Development

Successfully merging this pull request may close these issues.

4 participants