github.com/sacloud/libsacloud/v2@v2.32.3/helper/api/caller.go (about)

     1  // Copyright 2016-2022 The Libsacloud Authors
     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 api
    16  
    17  import (
    18  	"fmt"
    19  	"net/http"
    20  	"strings"
    21  	"time"
    22  
    23  	sacloudhttp "github.com/sacloud/go-http"
    24  	"github.com/sacloud/libsacloud/v2"
    25  	"github.com/sacloud/libsacloud/v2/helper/defaults"
    26  	"github.com/sacloud/libsacloud/v2/sacloud"
    27  	"github.com/sacloud/libsacloud/v2/sacloud/fake"
    28  	"github.com/sacloud/libsacloud/v2/sacloud/trace"
    29  	"github.com/sacloud/libsacloud/v2/sacloud/trace/otel"
    30  	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
    31  )
    32  
    33  // NewCaller 指定のオプションでsacloud.APICallerを構築して返す
    34  func NewCaller(opts ...*CallerOptions) sacloud.APICaller {
    35  	return newCaller(MergeOptions(opts...))
    36  }
    37  
    38  // NewCallerWithDefaults 指定のオプション+環境変数/プロファイルを用いてsacloud.APICallerを構築して返す
    39  //
    40  // DefaultOption()で得られる*CallerOptionsにoptsをマージしてからNewCallerが呼ばれる
    41  func NewCallerWithDefaults(opts *CallerOptions) (sacloud.APICaller, error) {
    42  	defaultOpts, err := DefaultOption()
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return NewCaller(defaultOpts, opts), nil
    47  }
    48  
    49  func newCaller(opts *CallerOptions) sacloud.APICaller {
    50  	// build http client
    51  	httpClient := http.DefaultClient
    52  	if opts.HTTPClient != nil {
    53  		httpClient = opts.HTTPClient
    54  	}
    55  	if opts.HTTPRequestTimeout > 0 {
    56  		httpClient.Timeout = time.Duration(opts.HTTPRequestTimeout) * time.Second
    57  	}
    58  	if opts.HTTPRequestTimeout == 0 {
    59  		httpClient.Timeout = 300 * time.Second // デフォルト値
    60  	}
    61  	if opts.HTTPRequestRateLimit > 0 {
    62  		httpClient.Transport = &sacloudhttp.RateLimitRoundTripper{RateLimitPerSec: opts.HTTPRequestRateLimit}
    63  	}
    64  	if opts.HTTPRequestRateLimit == 0 {
    65  		httpClient.Transport = &sacloudhttp.RateLimitRoundTripper{RateLimitPerSec: 10} // デフォルト値
    66  	}
    67  
    68  	retryMax := 0
    69  	if opts.RetryMax > 0 {
    70  		retryMax = opts.RetryMax
    71  	}
    72  
    73  	retryWaitMax := time.Duration(0)
    74  	if opts.RetryWaitMax > 0 {
    75  		retryWaitMax = time.Duration(opts.RetryWaitMax) * time.Second
    76  	}
    77  
    78  	retryWaitMin := time.Duration(0)
    79  	if opts.RetryWaitMin > 0 {
    80  		retryWaitMin = time.Duration(opts.RetryWaitMin) * time.Second
    81  	}
    82  
    83  	ua := fmt.Sprintf("libsacloud/%s", libsacloud.Version)
    84  	if opts.UserAgent != "" {
    85  		ua = opts.UserAgent
    86  	}
    87  
    88  	caller := &sacloud.Client{
    89  		AccessToken:       opts.AccessToken,
    90  		AccessTokenSecret: opts.AccessTokenSecret,
    91  		UserAgent:         ua,
    92  		AcceptLanguage:    opts.AcceptLanguage,
    93  		RetryMax:          retryMax,
    94  		RetryWaitMax:      retryWaitMax,
    95  		RetryWaitMin:      retryWaitMin,
    96  		HTTPClient:        httpClient,
    97  	}
    98  	sacloud.DefaultStatePollingTimeout = 72 * time.Hour
    99  
   100  	if opts.TraceAPI {
   101  		// note: exact once
   102  		trace.AddClientFactoryHooks()
   103  	}
   104  	if opts.TraceHTTP {
   105  		caller.HTTPClient.Transport = &sacloudhttp.TracingRoundTripper{
   106  			Transport: caller.HTTPClient.Transport,
   107  		}
   108  	}
   109  	if opts.OpenTelemetry {
   110  		otel.Initialize(opts.OpenTelemetryOptions...)
   111  		transport := caller.HTTPClient.Transport
   112  		if transport == nil {
   113  			transport = http.DefaultTransport
   114  		}
   115  		caller.HTTPClient.Transport = otelhttp.NewTransport(transport)
   116  	}
   117  
   118  	if opts.FakeMode {
   119  		if opts.FakeStorePath != "" {
   120  			fake.DataStore = fake.NewJSONFileStore(opts.FakeStorePath)
   121  		}
   122  		// note: exact once
   123  		fake.SwitchFactoryFuncToFake()
   124  
   125  		SetupFakeDefaults()
   126  	}
   127  
   128  	if opts.DefaultZone != "" {
   129  		sacloud.APIDefaultZone = opts.DefaultZone
   130  	}
   131  
   132  	if opts.APIRootURL != "" {
   133  		if strings.HasSuffix(opts.APIRootURL, "/") {
   134  			opts.APIRootURL = strings.TrimRight(opts.APIRootURL, "/")
   135  		}
   136  		sacloud.SakuraCloudAPIRoot = opts.APIRootURL
   137  	}
   138  
   139  	if len(opts.Zones) > 0 {
   140  		sacloud.SakuraCloudZones = opts.Zones
   141  	}
   142  	return caller
   143  }
   144  
   145  func SetupFakeDefaults() {
   146  	defaultInterval := 10 * time.Millisecond
   147  
   148  	// update default polling intervals: libsacloud/sacloud
   149  	sacloud.DefaultStatePollingInterval = defaultInterval
   150  	sacloud.DefaultDBStatusPollingInterval = defaultInterval
   151  	// update default polling intervals: libsacloud/helper/setup
   152  	defaults.DefaultDeleteWaitInterval = defaultInterval
   153  	defaults.DefaultProvisioningWaitInterval = defaultInterval
   154  	defaults.DefaultPollingInterval = defaultInterval
   155  	// update default polling intervals: libsacloud/helper/builder
   156  	defaults.DefaultNICUpdateWaitDuration = defaultInterval
   157  	// update default timeouts and span: libsacloud/helper/power
   158  	defaults.DefaultPowerHelperBootRetrySpan = defaultInterval
   159  	defaults.DefaultPowerHelperShutdownRetrySpan = defaultInterval
   160  	defaults.DefaultPowerHelperInitialRequestRetrySpan = defaultInterval
   161  	defaults.DefaultPowerHelperInitialRequestTimeout = defaultInterval * 100
   162  
   163  	fake.PowerOnDuration = time.Millisecond
   164  	fake.PowerOffDuration = time.Millisecond
   165  	fake.DiskCopyDuration = time.Millisecond
   166  }