github.com/sacloud/iaas-api-go@v1.12.0/helper/api/options.go (about) 1 // Copyright 2022-2023 The sacloud/iaas-api-go 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 "os" 20 "runtime" 21 22 client "github.com/sacloud/api-client-go" 23 "github.com/sacloud/api-client-go/profile" 24 "github.com/sacloud/iaas-api-go" 25 "github.com/sacloud/packages-go/envvar" 26 ) 27 28 var UserAgent = fmt.Sprintf( 29 "sacloud/iaas-api-go/v%s (%s/%s; +https://github.com/sacloud/iaas-api-go) %s", 30 iaas.Version, 31 runtime.GOOS, 32 runtime.GOARCH, 33 client.DefaultUserAgent, 34 ) 35 36 // CallerOptions iaas.APICallerを作成する際のオプション 37 type CallerOptions struct { 38 *client.Options 39 40 APIRootURL string 41 DefaultZone string 42 Zones []string 43 44 TraceAPI bool 45 FakeMode bool 46 FakeStorePath string 47 } 48 49 // DefaultOption 環境変数、プロファイルからCallerOptionsを組み立てて返す 50 // 51 // プロファイルは環境変数`SAKURACLOUD_PROFILE`または`USACLOUD_PROFILE`でプロファイル名が指定されていればそちらを優先し、 52 // 未指定の場合は通常のプロファイル処理(~/.usacloud/currentファイルから読み込み)される。 53 // 同じ項目を複数箇所で指定していた場合、環境変数->プロファイルの順で上書きされたものが返される 54 func DefaultOption() (*CallerOptions, error) { 55 return DefaultOptionWithProfile("") 56 } 57 58 // DefaultOptionWithProfile 環境変数、プロファイルからCallerOptionsを組み立てて返す 59 // 60 // プロファイルは引数を優先し、空の場合は環境変数`SAKURACLOUD_PROFILE`または`USACLOUD_PROFILE`が利用され、 61 // それも空の場合は通常のプロファイル処理(~/.usacloud/currentファイルから読み込み)される。 62 // 同じ項目を複数箇所で指定していた場合、環境変数->プロファイルの順で上書きされたものが返される 63 func DefaultOptionWithProfile(profileName string) (*CallerOptions, error) { 64 options, err := client.DefaultOptionWithProfile(profileName) 65 if err != nil { 66 return nil, err 67 } 68 69 fromEnv := OptionsFromEnv() 70 fromEnv.Options = options 71 72 fromProfile, err := OptionsFromProfile(profileName) 73 if err != nil { 74 return nil, err 75 } 76 fromProfile.Options = options 77 78 defaults := &CallerOptions{ 79 APIRootURL: iaas.SakuraCloudAPIRoot, 80 DefaultZone: iaas.APIDefaultZone, 81 Zones: iaas.SakuraCloudZones, 82 Options: &client.Options{ 83 UserAgent: UserAgent, 84 }, 85 } 86 87 return MergeOptions(defaults, fromEnv, fromProfile), nil 88 } 89 90 // OptionsFromEnv 環境変数からCallerOptionsを組み立てて返す 91 func OptionsFromEnv() *CallerOptions { 92 return &CallerOptions{ 93 Options: client.OptionsFromEnv(), 94 APIRootURL: envvar.StringFromEnv("SAKURACLOUD_API_ROOT_URL", ""), 95 DefaultZone: envvar.StringFromEnv("SAKURACLOUD_DEFAULT_ZONE", ""), 96 Zones: envvar.StringSliceFromEnv("SAKURACLOUD_ZONES", []string{}), 97 98 TraceAPI: profile.EnableAPITrace(envvar.StringFromEnv("SAKURACLOUD_TRACE", "")), 99 100 FakeMode: os.Getenv("SAKURACLOUD_FAKE_MODE") != "", 101 FakeStorePath: envvar.StringFromEnv("SAKURACLOUD_FAKE_STORE_PATH", ""), 102 } 103 } 104 105 // OptionsFromProfile 指定のプロファイルからCallerOptionsを組み立てて返す 106 // プロファイル名に空文字が指定された場合はカレントプロファイルが利用される 107 func OptionsFromProfile(profileName string) (*CallerOptions, error) { 108 options, err := client.OptionsFromProfile(profileName) 109 if err != nil { 110 return nil, err 111 } 112 config := options.ProfileConfigValue() 113 return &CallerOptions{ 114 Options: options, 115 APIRootURL: config.APIRootURL, 116 DefaultZone: config.DefaultZone, 117 Zones: config.Zones, 118 TraceAPI: config.EnableAPITrace(), 119 FakeMode: config.FakeMode, 120 FakeStorePath: config.FakeStorePath, 121 }, nil 122 } 123 124 // MergeOptions 指定のCallerOptionsの非ゼロ値フィールドをoのコピーにマージして返す 125 func MergeOptions(opts ...*CallerOptions) *CallerOptions { 126 merged := &CallerOptions{} 127 for _, opt := range opts { 128 if opt.Options != nil { 129 var opts []*client.Options 130 if merged.Options != nil { 131 opts = append(opts, merged.Options) 132 } 133 opts = append(opts, opt.Options) 134 merged.Options = client.MergeOptions(opts...) 135 } 136 if opt.APIRootURL != "" { 137 merged.APIRootURL = opt.APIRootURL 138 } 139 if opt.DefaultZone != "" { 140 merged.DefaultZone = opt.DefaultZone 141 } 142 if len(opt.Zones) > 0 { 143 merged.Zones = opt.Zones 144 } 145 146 // Note: bool値は一度trueにしたらMergeでfalseになることがない 147 if opt.TraceAPI { 148 merged.TraceAPI = true 149 } 150 if opt.FakeMode { 151 merged.FakeMode = true 152 } 153 if opt.FakeStorePath != "" { 154 merged.FakeStorePath = opt.FakeStorePath 155 } 156 } 157 return merged 158 }