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 }