pkg/export/gce_token_source.go (67 lines of code) (raw):

// Copyright 2015 The Kubernetes Authors. // Modifications copyright (C) 2020 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License 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. package export import ( "context" "encoding/json" "fmt" "net/http" "strings" "time" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "golang.org/x/time/rate" "google.golang.org/api/googleapi" ) const ( // Max QPS to allow through to the token URL. tokenURLQPS = .05 // back off to once every 20 seconds when failing // Maximum burst of requests to token URL before limiting. tokenURLBurst = 3 ) // AltTokenSource is the structure holding the data for the functionality needed to generates tokens. type AltTokenSource struct { oauthClient *http.Client tokenURL string tokenBody string throttle *rate.Limiter } // Token returns a token which may be used for authentication. func (a *AltTokenSource) Token() (*oauth2.Token, error) { r := a.throttle.Reserve() if !r.OK() { return nil, fmt.Errorf("rate limiter (rate: %f, burst: %d) cannot provide the requested token", a.throttle.Limit(), a.throttle.Burst()) } time.Sleep(r.Delay()) return a.token() } func (a *AltTokenSource) token() (*oauth2.Token, error) { req, err := http.NewRequest(http.MethodPost, a.tokenURL, strings.NewReader(a.tokenBody)) if err != nil { return nil, err } res, err := a.oauthClient.Do(req) if err != nil { return nil, err } defer res.Body.Close() if err := googleapi.CheckResponse(res); err != nil { return nil, err } var tok struct { AccessToken string `json:"accessToken"` ExpireTime time.Time `json:"expireTime"` } if err := json.NewDecoder(res.Body).Decode(&tok); err != nil { return nil, err } return &oauth2.Token{ AccessToken: tok.AccessToken, Expiry: tok.ExpireTime, }, nil } // NewAltTokenSource constructs a new alternate token source for generating tokens. func NewAltTokenSource(tokenURL, tokenBody string) oauth2.TokenSource { client := oauth2.NewClient(context.Background(), google.ComputeTokenSource("")) a := &AltTokenSource{ oauthClient: client, tokenURL: tokenURL, tokenBody: tokenBody, throttle: rate.NewLimiter(tokenURLQPS, tokenURLBurst), } return oauth2.ReuseTokenSource( /* token */ nil, a) }