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

chore: logins return Sessions #8883

Merged
merged 9 commits into from
Mar 19, 2024
Merged

chore: logins return Sessions #8883

merged 9 commits into from
Mar 19, 2024

Conversation

wes-turner
Copy link
Contributor

@wes-turner wes-turner commented Feb 23, 2024

Logins used to return an intermediate UsernameTokenPair that itself was used to create Sessions. We did it this way because the job of login is to find/create a valid token. But because login itself is a user-facing command, and tokens are an implementation detail most people don't care about, this patch updates the login API to just return a Session (the thing most users cared about in the first place).

If a user really wants to get a token, they can always access the token in the Session.

Additionally as a part of this patch, the UsernameTokenPair class has been removed -- it was kind of an in-between abstraction to make it easier for callers of login to create sessions.

This change also contains new BaseSession.with_retry to modify retries (by creating new sessions). We needed some mechanism for users to set retry to something other than the default, and passing retry into login would have been a weird interface (what does the retry of the eventual session have to do with logging in?).

MD-283

Description

Test Plan

Commentary (optional)

Checklist

  • Changes have been manually QA'd
  • User-facing API changes need the "User-facing API Change" label.
  • Release notes should be added as a separate file under docs/release-notes/.
    See Release Note for details.
  • Licenses should be included for new code which was copied and/or modified from any external code.

Ticket

@cla-bot cla-bot bot added the cla-signed label Feb 23, 2024
Copy link

netlify bot commented Feb 23, 2024

Deploy Preview for determined-ui ready!

Name Link
🔨 Latest commit f6251f0
🔍 Latest deploy log https://app.netlify.com/sites/determined-ui/deploys/65f9b5cd2ed2e20008152b01
😎 Deploy Preview https://deploy-preview-8883--determined-ui.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link

codecov bot commented Feb 23, 2024

Codecov Report

Attention: Patch coverage is 78.78788% with 14 lines in your changes are missing coverage. Please review.

Project coverage is 47.75%. Comparing base (fa43bff) to head (f6251f0).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8883      +/-   ##
==========================================
+ Coverage   47.74%   47.75%   +0.01%     
==========================================
  Files        1161     1161              
  Lines      143093   143070      -23     
  Branches     2372     2370       -2     
==========================================
+ Hits        68318    68330      +12     
+ Misses      74622    74587      -35     
  Partials      153      153              
Flag Coverage Δ
backend 42.74% <ø> (+0.06%) ⬆️
harness 63.96% <78.78%> (+<0.01%) ⬆️
web 40.86% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
harness/determined/cli/_util.py 68.08% <100.00%> (-0.67%) ⬇️
harness/determined/common/api/__init__.py 100.00% <100.00%> (ø)
harness/determined/common/api/authentication.py 85.44% <100.00%> (-0.33%) ⬇️
...rness/determined/common/experimental/determined.py 41.21% <100.00%> (-0.36%) ⬇️
harness/determined/launch/deepspeed.py 91.46% <100.00%> (-0.11%) ⬇️
harness/determined/launch/horovod.py 94.56% <100.00%> (-0.12%) ⬇️
harness/tests/checkpoints/test_checkpoint.py 100.00% <ø> (ø)
harness/tests/cli/test_auth.py 93.85% <100.00%> (+0.03%) ⬆️
harness/tests/cli/test_experiment.py 100.00% <100.00%> (ø)
.../determined/common/experimental/test_checkpoint.py 94.82% <100.00%> (-0.18%) ⬇️
... and 16 more

... and 4 files with indirect coverage changes

@wes-turner wes-turner force-pushed the wes/login-returns-session branch 3 times, most recently from 9dc6474 to 3da73c1 Compare March 1, 2024 21:24
@wes-turner wes-turner marked this pull request as ready for review March 4, 2024 20:05
@wes-turner wes-turner requested a review from a team as a code owner March 4, 2024 20:05
Copy link
Member

@rb-determined-ai rb-determined-ai left a comment

Choose a reason for hiding this comment

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

My name is @rb-determined-ai, and I approve of this change.

But also, what if UnauthSession had login and login_with_cache on it? That might be a more natural way to configure the retries.

Or it might be making the relationship between objects too complicated (that is how I felt, because I did consider that at some point).

But I wanted to voice it in case you hadn't thought of it and you loved the idea.

@wes-turner
Copy link
Contributor Author

wes-turner commented Mar 4, 2024

But also, what if UnauthSession had login and login_with_cache on it? That might be a more natural way to configure the retries.

Or it might be making the relationship between objects too complicated (that is how I felt, because I did consider that at some point).

But I wanted to voice it in case you hadn't thought of it and you loved the idea.

In code,

class UnauthSession(BaseSession):
  def login(self, user, password) -> Session:
    ...
  def login_with_cache(self, user, password) -> Session:
    ...

sess = api.UnauthSession(master, cert).login(user, password)

I like it. I don't know if I prefer it on the whole (makes creating a new session a little more awkward), but I do think it's a better abstraction to have implemented.

FWIW, I think adding an optional max_retries to UnauthSession.login is no better than max_retries on authentication.login, so in the case of the above I still prefer a BaseSession.with_retry.

@rb-determined-ai
Copy link
Member

rb-determined-ai commented Mar 4, 2024

FWIW, I think adding an optional max_retries to UnauthSession.login is no better than max_retries on authentication.login, so in the case of the above I still prefer a BaseSession.with_retry.

I mean, I think you would put max_retries on UnauthSession not on its .login()

@azhou-determined
Copy link
Contributor

i had originally thought login methods returning a session would be a great abstraction. the more i look at it/think about it, the less sure i am.

i think you're right that a parameter like retry shouldn't have anything to do with logging in. but then why should login methods return a session? seems like we're blurring abstractions somewhere. feels like a "pure" login method should return nothing (or at most a bool indicating whether login was successful or not). and if i keep with this train of thought, maybe logically all login should do is authenticate and persist the login token. and maybe get_current_session would be a separate method that returns the session.

i don't know how feasible this is, so take this however seriously you want. it's probably not worth the effort as i don't see it providing much value, and i think what you have is fine. just my $0.02.

@wes-turner
Copy link
Contributor Author

FWIW, I think adding an optional max_retries to UnauthSession.login is no better than max_retries on authentication.login, so in the case of the above I still prefer a BaseSession.with_retry.

I mean, I think you would put max_retries on UnauthSession not on its .login()

Oh... Yeah. That's better.

Unlike ``login``, this function may not send a login request to the master. It will instead
first attempt to find a valid token in the TokenStore, and only if that fails will it post a
login request to the master to generate a new one. As with ``login``, the token is then baked
into a new api.Session object to sign future communication with master.
Copy link
Contributor

@azhou-determined azhou-determined Mar 7, 2024

Choose a reason for hiding this comment

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

quotes api.Session

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Thanks!

Copy link
Contributor

@azhou-determined azhou-determined left a comment

Choose a reason for hiding this comment

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

lgtm

@wes-turner
Copy link
Contributor Author

But also, what if UnauthSession had login and login_with_cache on it? That might be a more natural way to configure the retries.

I do like this idea. A lot. But I'm not sure how much more I like it than what's implemented, and keeping in mind ROI I don't think it's worth working out.

@wes-turner wes-turner requested a review from a team as a code owner March 15, 2024 22:29
@@ -75,8 +75,7 @@ def main():
notebook_server = f"https://127.0.0.1:{port}/proxy/{notebook_id}"
master_url = api.canonicalize_master_url(os.environ["DET_MASTER"])
cert = certs.default_load(master_url)
utp = authentication.login_with_cache(info.master_url, cert=cert)
sess = api.Session(master_url, utp, cert)
sess = authentication.login_with_cache(master_url, cert=cert)
Copy link
Contributor Author

@wes-turner wes-turner Mar 15, 2024

Choose a reason for hiding this comment

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

Unrelated to the change; this looks like a bugfix. info had not been in scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Decided to not implement a regression test. This doesn't seem like functionality we care much about.

import json as _json
from typing import Any, Dict, Optional, Tuple, Union
from typing import Any, Dict, Optional, Tuple, TypeVar, Union

import requests
import urllib3

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this will also need to be updated

utp = authentication.login("http://127.0.0.1:8080", "admin", "", cert)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed. I hadn't known that **/*.py glob skipped hidden directories. Thanks for catching this.

@wes-turner wes-turner requested review from a team as code owners March 18, 2024 17:05
Copy link
Contributor

@loksonarius loksonarius left a comment

Choose a reason for hiding this comment

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

Approving CI changes on behalf of infra

@wes-turner wes-turner removed the request for review from gt2345 March 18, 2024 18:18
Used to return an intermediate `UsernameTokenPair` that itself was used
for sessions. This class has been removed.

Also contains new `BaseSession.with_retry` to modify retries (by
creating new sessions).
Also includes a bugfix in `check_idle.py`, I think, where master wasn't
being propagated.
@wes-turner wes-turner merged commit a603f4c into main Mar 19, 2024
103 checks passed
@wes-turner wes-turner deleted the wes/login-returns-session branch March 19, 2024 17:50
maxrussell pushed a commit that referenced this pull request Mar 21, 2024
Logins used to return an intermediate UsernameTokenPair that itself was used to create Sessions. We did it this way because the job of login is to find/create a valid token. But because login itself is a user-facing command, and tokens are an implementation detail most people don't care about, this patch updates the login API to just return a Session (the thing most users cared about in the first place).

If a user really wants to get a token, they can always access the token in the Session.

Additionally as a part of this patch, the UsernameTokenPair class has been removed -- it was kind of an in-between abstraction to make it easier for callers of login to create sessions.

This change also contains new BaseSession.with_retry to modify retries (by creating new sessions). We needed some mechanism for users to set retry to something other than the default, and passing retry into login would have been a weird interface (what does the retry of the eventual session have to do with logging in?).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants