...

Source file src/github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/clientconfig/config.go

Documentation: github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/clientconfig

     1  // Copyright 2022 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package clientconfig
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"net/http"
    21  	"time"
    22  
    23  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/logger"
    24  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/gcp"
    25  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
    26  
    27  	"github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl"
    28  	"golang.org/x/oauth2/google"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/klog/v2"
    31  )
    32  
    33  var nonretryable = dcl.Retryability{Retryable: false}
    34  
    35  type Options struct {
    36  	UserAgent string
    37  
    38  	// UserProjectOverride provides the option to use the resource project for preconditions, quota, and billing,
    39  	// instead of the project the credentials belong to; false by default
    40  	UserProjectOverride bool
    41  
    42  	// BillingProject is the project used by the TF provider and DCL client to determine preconditions,
    43  	// quota, and billing if UserProjectOverride is set to true. If this field is empty,
    44  	// but UserProjectOverride is set to true, resource project will be used.
    45  	BillingProject string
    46  
    47  	// HTTPClient allows us to specify the HTTP client to use with DCL.
    48  	// This is particularly useful in mocks/tests.
    49  	HTTPClient *http.Client
    50  }
    51  
    52  func New(ctx context.Context, opt Options) (*dcl.Config, error) {
    53  	if opt.UserAgent == "" {
    54  		opt.UserAgent = gcp.KCCUserAgent
    55  	}
    56  
    57  	if opt.HTTPClient == nil {
    58  		httpClient, err := google.DefaultClient(ctx, gcp.ClientScopes...)
    59  		if err != nil {
    60  			return nil, fmt.Errorf("error creating the http client to be used by DCL: %w", err)
    61  		}
    62  		opt.HTTPClient = httpClient
    63  	}
    64  
    65  	configOptions := []dcl.ConfigOption{
    66  		dcl.WithHTTPClient(opt.HTTPClient),
    67  		dcl.WithUserAgent(opt.UserAgent),
    68  		dcl.WithLogger(logger.SimpleDCLLogger()),
    69  		// ConfigControllerInstance takes ~17 minutes to be created.
    70  		dcl.WithTimeout(30 * time.Minute),
    71  		dcl.WithCodeRetryability(
    72  			map[int]dcl.Retryability{
    73  				// ComputeFirewallPolicy uses error code 403 for quota exceeded
    74  				// errors. Quota exceeded errors should not be retryable.
    75  				403: nonretryable,
    76  				// Quota exceeded errors are usually surfaced by a 429 error
    77  				// code in GCP. Quota exceeded errors should not be retryable.
    78  				429: nonretryable,
    79  			},
    80  		),
    81  	}
    82  	if opt.UserProjectOverride {
    83  		configOptions = append(configOptions, dcl.WithUserProjectOverride())
    84  	}
    85  	if opt.BillingProject != "" {
    86  		configOptions = append(configOptions, dcl.WithBillingProject(opt.BillingProject))
    87  	}
    88  	dclConfig := dcl.NewConfig(configOptions...)
    89  	return dclConfig, nil
    90  }
    91  
    92  // NewForIntegrationTest creates a dcl.Config for use in integration tests.
    93  // Deprecated: Prefer using a harness.
    94  func NewForIntegrationTest() *dcl.Config {
    95  	ctx := context.TODO()
    96  	opt := Options{
    97  		UserAgent: "kcc/dev",
    98  	}
    99  
   100  	config, err := New(ctx, opt)
   101  	if err != nil {
   102  		klog.Fatalf("error from NewForIntegrationTest: %v", err)
   103  	}
   104  	return config
   105  }
   106  
   107  func CopyAndModifyForKind(dclConfig *dcl.Config, kind string) *dcl.Config {
   108  	// Configure a custom DCL timeout.
   109  	if timeout, ok := kindToTimeout[kind]; ok {
   110  		return dclConfig.Clone(dcl.WithTimeout(timeout))
   111  	}
   112  	return dclConfig.Clone()
   113  }
   114  
   115  // SetUserAgentWithBlueprintAttribution returns a new DCL Config with the user agent containing the blueprint attribution
   116  // if the resource has the blueprint attribution annotation. Otherwise, the existing DCL Config is unmodified and returned.
   117  func SetUserAgentWithBlueprintAttribution(dclConfig *dcl.Config, resource metav1.Object) *dcl.Config {
   118  	bp, found := k8s.GetAnnotation(k8s.BlueprintAttributionAnnotation, resource)
   119  	if !found {
   120  		return dclConfig
   121  	}
   122  	userAgentWithBlueprintAttribution := fmt.Sprintf("%v blueprints/%v", gcp.KCCUserAgent, bp)
   123  	newConfig := dclConfig.Clone(dcl.WithUserAgent(userAgentWithBlueprintAttribution))
   124  	return newConfig
   125  }
   126  

View as plain text