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

Respect proxy settings and timeout in token command #410

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

pmatseykanets
Copy link
Contributor

@pmatseykanets pmatseykanets commented Jan 8, 2025

Ref rancher/rancher#48631

The dedicated http clients in the token command that are used for various needs currently don't respect proxy and timeout settings.

This PR makes sure that the http client is reused and respect proxy and timeout settings.

@pmatseykanets pmatseykanets self-assigned this Jan 8, 2025
@pmatseykanets pmatseykanets requested a review from a team as a code owner January 8, 2025 18:58
server := ctx.String("server")
if server == "" {
return errors.New("name of rancher server is required")
}
url, err := url2.Parse(server)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Avoid shadowing the url package.

if err != nil {
return err
}

if err := cacheCredential(ctx, newCred, fmt.Sprintf("%s_%s", userID, clusterID)); err != nil {
client, err := newHTTPClient(serverConfig, tlsConfig)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reuse the common http client for all subsequent requests.

@@ -214,20 +228,15 @@ func deleteCachedCredential(ctx *cli.Context) error {
for _, key := range ctx.Args() {
customPrint(fmt.Sprintf("removing [%s]", key))
for _, server := range cf.Servers {
server.KubeCredentials[key] = nil
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was prone to panics.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice!

return token, nil
}

func samlAuth(input *LoginInput, client *http.Client) (managementClient.Token, error) {
func samlAuth(client *http.Client, input *LoginInput) (managementClient.Token, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The idiomatic approach is to list arguments in the order of increasing specificity. This way all dependencies come first.

// timeout for user to login and get token
timeout := time.NewTicker(15 * time.Minute)
// Timeout for the login flow.
timeout := time.NewTimer(15 * time.Minute)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Use the time.Timer instead as we expect to receive the overall flow timeout signal only once.

Copy link
Contributor

Choose a reason for hiding this comment

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

I feel there is a better way to do this poll and timeout, but I wouldn't try to change the logic without tests here.


return token, nil

case <-timeout.C:
break
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was no-op as it doesn't break out of the loop.


case <-interrupt:
customPrint("received interrupt")
break
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same here.

var response []byte

req, err := http.NewRequest(method, url, body)
func doRequest(client *http.Client, req *http.Request) (*http.Response, []byte, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Return the http.Response as the consuming code should be checking the returned status code in most/all cases.

Comment on lines -138 to -140
if ctx.Bool("delete") {
return deleteCachedCredential(ctx)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems like it might've been a flag in the past, which is no longer true. We use the delete subcommand for this.

Copy link
Contributor

Choose a reason for hiding this comment

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

One of the reason because we should try to avoid passing the *cli.Context, and have a Config struct to pass. But that's a refactor for another day.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IMHO passing the context or not is a different story.

The issue here is that it seems like that delete was a flag
rancher token --delete <name>
and then turned into an argument (subcommand)
rancher token delete <name>

req.Header.Set("content-type", "application/json")
req.Header.Set("accept", "application/json")

client.Timeout = 300 * time.Second
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This seems unnecessary. There is nothing specific or unusual about requesting an auth token that might require a custom 5 min timeout.

req.Header.Set("content-type", "application/json")
req.Header.Set("accept", "application/json")

client.Timeout = 150 * time.Second
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same here. There is nothing specific or unusual about this request that might require a custom timeout.

Comment on lines +392 to +395
resp, respBody, err := doRequest(client, req)
if err == nil && resp.StatusCode != http.StatusOK {
err = fmt.Errorf("unexpected http status code %d", resp.StatusCode)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel having the err check before is more idiomatic, wdyt?

resp, respBody, err := doRequest(client, req)
if err != nil {
	return token, nil
}
if resp.StatusCode != http.StatusOK {
	return token, fmt.Errorf("unexpected http status code %d", resp.StatusCode)
}

I'm also confused about the return token, nil. Is it ok? Should we at least log the error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only idiomatic part is to explicitly check for the error if one is returned to the caller, which we do. There is no prescribed way of doing it though.
In this particular case if the request succeeds err == nil but the http status code is anything but the OK we want to fail and so we assign an error first L393-L395.
Then we cover both cases and check for err != nil.

Copy link
Contributor

@enrichman enrichman left a comment

Choose a reason for hiding this comment

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

A couple of comments, but it LGTM

// timeout for user to login and get token
timeout := time.NewTicker(15 * time.Minute)
// Timeout for the login flow.
timeout := time.NewTimer(15 * time.Minute)
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel there is a better way to do this poll and timeout, but I wouldn't try to change the logic without tests here.

Comment on lines 93 to 96
resp, respBody, err := doRequest(client, req)
if err == nil && resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected http status code %d", resp.StatusCode)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above, can we invert the check?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was a bad copy-paste from one of the my previous iterations. We shouldn't invert anything. All we need is to set the err. Fixed in 649c29d.

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

Successfully merging this pull request may close these issues.

2 participants