proxylb.go raw
1 // Copyright 2022-2025 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 naked
16
17 import (
18 "encoding/json"
19 "strings"
20 "time"
21
22 "github.com/sacloud/iaas-api-go/types"
23 )
24
25 // ProxyLB エンハンスドロードバランサ
26 type ProxyLB struct {
27 ID types.ID `json:",omitempty" yaml:"id,omitempty" structs:",omitempty"`
28 Name string `json:",omitempty" yaml:"name,omitempty" structs:",omitempty"`
29 Description string `yaml:"description"`
30 Tags types.Tags `yaml:"tags"`
31 Icon *Icon `json:",omitempty" yaml:"icon,omitempty" structs:",omitempty"`
32 CreatedAt *time.Time `json:",omitempty" yaml:"created_at,omitempty" structs:",omitempty"`
33 ModifiedAt *time.Time `json:",omitempty" yaml:"modified_at,omitempty" structs:",omitempty"`
34 Availability types.EAvailability `json:",omitempty" yaml:"availability,omitempty" structs:",omitempty"`
35 Provider *Provider `json:",omitempty" yaml:"provider,omitempty" structs:",omitempty"`
36 Settings *ProxyLBSettings `json:",omitempty" yaml:"settings,omitempty" structs:",omitempty"`
37 SettingsHash string `json:",omitempty" yaml:"settings_hash,omitempty" structs:",omitempty"`
38 Status *ProxyLBStatus `json:",omitempty" yaml:"status,omitempty" structs:",omitempty"`
39
40 // ServiceClass [HACK] ServiceClassはプランとリージョンから決定するためjson.Marshalerで出力する。
41 // see https://github.com/sacloud/libsacloud/issues/577
42 ServiceClass string `json:",omitempty" yaml:"service_class,omitempty" structs:",omitempty"`
43 Plan types.EProxyLBPlan `json:"-"`
44 }
45
46 // MarshalJSON implements json.Marshaler
47 func (p *ProxyLB) MarshalJSON() ([]byte, error) {
48 if p.Status != nil && p.Plan != types.EProxyLBPlan(0) {
49 p.ServiceClass = types.ProxyLBServiceClass(p.Plan, p.Status.Region)
50 }
51
52 type alias ProxyLB
53 tmp := alias(*p)
54 return json.Marshal(&tmp)
55 }
56
57 // UnmarshalJSON implements json.Unmarshaler
58 func (p *ProxyLB) UnmarshalJSON(b []byte) error {
59 type alias ProxyLB
60 var tmp alias
61 if err := json.Unmarshal(b, &tmp); err != nil {
62 return err
63 }
64
65 tmp.Plan = types.ProxyLBPlanFromServiceClass(tmp.ServiceClass)
66 *p = ProxyLB(tmp)
67 return nil
68 }
69
70 // ProxyLBPlanChange エンハンスドロードバランサのプラン変更
71 type ProxyLBPlanChange struct {
72 ServiceClass string `yaml:"service_class"`
73 }
74
75 // ProxyLBSettingsUpdate エンハンスドロードバランサ
76 type ProxyLBSettingsUpdate struct {
77 Settings *ProxyLBSettings `json:",omitempty" yaml:"settings,omitempty" structs:",omitempty"`
78 SettingsHash string `json:",omitempty" yaml:"settings_hash,omitempty" structs:",omitempty"`
79 }
80
81 // ProxyLBSettings エンハンスドロードバランサ設定
82 type ProxyLBSettings struct {
83 ProxyLB *ProxyLBSetting `json:",omitempty" yaml:"proxy_lb,omitempty" structs:",omitempty"`
84 }
85
86 // ProxyLBSetting エンハンスドロードバランサ設定
87 type ProxyLBSetting struct {
88 HealthCheck ProxyLBHealthCheck `yaml:"health_check"` // ヘルスチェック
89 SorryServer ProxyLBSorryServer `yaml:"sorry_server"` // ソーリーサーバー
90 BindPorts []*ProxyLBBindPorts `yaml:"bind_ports"` // プロキシ方式(プロトコル&ポート)
91 Servers []ProxyLBServer `yaml:"servers"` // サーバー
92 Rules []ProxyLBRule `yaml:"rules"` // 振り分けルール
93 LetsEncrypt *ProxyLBACMESetting `json:",omitempty" yaml:"lets_encrypt,omitempty" structs:",omitempty"` // Let's encryptでの証明書取得設定
94 StickySession ProxyLBStickySession `yaml:"sticky_session"` // StickySession
95 Timeout ProxyLBTimeout `json:",omitempty" yaml:"timeout,omitempty" structs:",omitempty"` // タイムアウト
96 Gzip ProxyLBGzip `yaml:"gzip"` // Gzip
97 BackendHttpKeepAlive *ProxyLBBackendHTTPKeepAlive `json:",omitempty" yaml:",backend_http_keey_alive,omitempty" structs:",omitempty"` // 実サーバとのHTTP持続接続
98 MonitoringSuiteLog *MonitoringSuiteLog `json:",omitempty" yaml:"monitoring_suite_log,omitempty" structs:",omitempty"`
99 ProxyProtocol ProxyLBProxyProtocol `yaml:"proxy_protocol"`
100 Syslog ProxyLBSyslog `yaml:"syslog"`
101 }
102
103 // MarshalJSON nullの場合に空配列を出力するための実装
104 func (s ProxyLBSetting) MarshalJSON() ([]byte, error) {
105 if s.BindPorts == nil {
106 s.BindPorts = make([]*ProxyLBBindPorts, 0)
107 }
108 if s.Servers == nil {
109 s.Servers = make([]ProxyLBServer, 0)
110 }
111 if s.Rules == nil {
112 s.Rules = make([]ProxyLBRule, 0)
113 }
114 // syslogは値がないと400エラーになるため両方空の場合はポートのデフォルト値だけ設定しておく
115 if s.Syslog.Server == "" && s.Syslog.Port == 0 {
116 s.Syslog.Port = 514
117 }
118
119 type alias ProxyLBSetting
120 tmp := alias(s)
121 return json.Marshal(&tmp)
122 }
123
124 // ProxyLBHealthCheck ヘルスチェック
125 type ProxyLBHealthCheck struct {
126 Protocol types.EProxyLBHealthCheckProtocol `json:",omitempty" yaml:"protocol,omitempty" structs:",omitempty"`
127 Path string `json:",omitempty" yaml:"path,omitempty" structs:",omitempty"`
128 Host string `json:",omitempty" yaml:"host,omitempty" structs:",omitempty"`
129 DelayLoop int `json:",omitempty" yaml:"delay_loop,omitempty" structs:",omitempty"`
130 }
131
132 // ProxyLBSorryServer ソーリーサーバ設定
133 type ProxyLBSorryServer struct {
134 IPAddress string `yaml:"ip_address"`
135 Port *int `yaml:"port"`
136 }
137
138 // ProxyLBBindPorts プロキシ方式
139 type ProxyLBBindPorts struct {
140 ProxyMode types.EProxyLBProxyMode `json:",omitempty" yaml:"proxy_mode,omitempty" structs:",omitempty"` // モード(プロトコル)
141 Port int `json:",omitempty" yaml:"port,omitempty" structs:",omitempty"` // ポート
142 RedirectToHTTPS bool `json:"RedirectToHttps" yaml:"redirect_to_https"` // HTTPSへのリダイレクト(モードがhttpの場合のみ)
143 SupportHTTP2 bool `json:"SupportHttp2" yaml:"support_http2"` // HTTP/2のサポート(モードがhttpsの場合のみ)
144 AddResponseHeader []*ProxyLBResponseHeader `json:",omitempty" yaml:"add_response_header,omitempty" structs:",omitempty"` // レスポンスヘッダ
145 SSLPolicy string `json:",omitempty" yaml:"ssl_policy,omitempty" structs:",omitempty"` // SSLポリシー
146 }
147
148 // ProxyLBResponseHeader ポートごとの追加レスポンスヘッダ
149 type ProxyLBResponseHeader struct {
150 Header string // ヘッダ名称(英字, 数字, ハイフン)
151 Value string // 値(英字, 数字, 半角スペース, 一部記号(!#$%&'()*+,-./:;<=>?@[]^_`{|}~))
152 }
153
154 // ProxyLBServer ProxyLB配下のサーバー
155 type ProxyLBServer struct {
156 IPAddress string `json:",omitempty" yaml:"ip_address,omitempty" structs:",omitempty"` // IPアドレス
157 Port int `json:",omitempty" yaml:"port,omitempty" structs:",omitempty"` // ポート
158 ServerGroup string `yaml:"server_group"` // サーバグループ
159 Enabled bool // 有効/無効
160 }
161
162 // ProxyLBRule ProxyLBの振り分けルール
163 type ProxyLBRule struct {
164 // 条件部
165 Host string `json:",omitempty" yaml:"host,omitempty" structs:",omitempty"` // ホストヘッダのパターン(ワイルドカードとして?と*が利用可能)
166 Path string `json:",omitempty" yaml:"path,omitempty" structs:",omitempty"` // パス
167
168 SourceIPs string `json:",omitempty" yaml:"source_ips,omitempty" structs:",omitempty"`
169
170 RequestHeaderName string `json:",omitempty" yaml:"request_header_name,omitempty" structs:",omitempty"`
171 RequestHeaderValue string `json:",omitempty" yaml:"request_header_value,omitempty" structs:",omitempty"`
172 RequestHeaderValueIgnoreCase bool `yaml:"request_header_value_ignore_case"`
173 RequestHeaderValueNotMatch bool `yaml:"request_header_value_not_match"`
174
175 // アクション部
176 Action types.EProxyLBRuleAction `json:",omitempty" yaml:"action,omitempty" structs:",omitempty"` // forward(実サーバへ転送) | redirect | fixed(固定レスポンス)
177 ServerGroup string `json:",omitempty" yaml:"server_group,omitempty" structs:",omitempty"`
178
179 RedirectLocation string `json:",omitempty" yaml:"redirect_location,omitempty" structs:",omitempty"`
180 RedirectStatusCode string `json:",omitempty" yaml:"redirect_status_code,omitempty" structs:",omitempty"` // 301 | 302
181
182 FixedStatusCode string `json:",omitempty" yaml:"fixed_status_code,omitempty" structs:",omitempty"`
183 FixedContentType types.EProxyLBFixedContentType `json:",omitempty" yaml:"fixed_content_type,omitempty" structs:",omitempty"`
184 FixedMessageBody string `json:",omitempty" yaml:"fixed_message_body,omitempty" structs:",omitempty"`
185 }
186
187 // ProxyLBACMESetting Let's Encryptでの証明書取得設定
188 type ProxyLBACMESetting struct {
189 Enabled bool `yaml:"enabled"`
190 CommonName string `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
191 SubjectAltNames []string `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
192 }
193
194 // MarshalJSON SubjectAltNamesをスライスから文字列にする
195 func (p ProxyLBACMESetting) MarshalJSON() ([]byte, error) {
196 type tmpSetting struct {
197 Enabled bool `yaml:"enabled"`
198 CommonName string `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
199 SubjectAltNames string `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
200 }
201 tmp := tmpSetting{
202 Enabled: p.Enabled,
203 CommonName: p.CommonName,
204 SubjectAltNames: strings.Join(p.SubjectAltNames, ","), // Note: カンマ区切りで統一
205 }
206 return json.Marshal(&tmp)
207 }
208
209 // UnmarshalJSON SubjectAltNamesを文字列からスライスにする
210 func (p *ProxyLBACMESetting) UnmarshalJSON(data []byte) error {
211 type tmpSetting struct {
212 Enabled bool `yaml:"enabled"`
213 CommonName string `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
214 SubjectAltNames string `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
215 }
216 var setting *tmpSetting
217 if err := json.Unmarshal(data, &setting); err != nil {
218 return err
219 }
220
221 *p = ProxyLBACMESetting{
222 Enabled: setting.Enabled,
223 CommonName: setting.CommonName,
224 SubjectAltNames: strings.FieldsFunc(setting.SubjectAltNames, func(r rune) bool {
225 return r == ' ' || r == ',' || r == '\n'
226 }),
227 }
228 return nil
229 }
230
231 // ProxyLBStickySession セッション維持(Sticky session)設定
232 type ProxyLBStickySession struct {
233 Enabled bool `yaml:"enabled"`
234 Method string `json:",omitempty" yaml:"method,omitempty" structs:",omitempty"`
235 }
236
237 // ProxyLBGzip Gzip圧縮設定
238 type ProxyLBGzip struct {
239 Enabled bool `yaml:"enabled"`
240 }
241
242 type ProxyLBBackendHTTPKeepAlive struct {
243 Mode types.EProxyLBBackendHttpKeepAlive `json:",omitempty" yaml:"mode,omitempty" structs:",omitempty"`
244 }
245
246 // ProxyLBProxyProtocol ProxyProtocol(v2)の有効設定
247 type ProxyLBProxyProtocol struct {
248 Enabled bool `yaml:"enabled"`
249 }
250
251 // ProxyLBSyslog Syslog設定
252 type ProxyLBSyslog struct {
253 Server string `yaml:"server"`
254 Port int `yaml:"port"`
255 }
256
257 // ProxyLBTimeout 実サーバの通信タイムアウト
258 type ProxyLBTimeout struct {
259 InactiveSec int `json:",omitempty" yaml:"inactive_sec" structs:",omitempty"` // 10から600まで1秒刻みで設定可
260 }
261
262 // ProxyLBStatus ステータス
263 type ProxyLBStatus struct {
264 UseVIPFailover bool `yaml:"use_vip_failover"`
265 Region types.EProxyLBRegion `json:",omitempty" yaml:"region,omitempty" structs:",omitempty"`
266 ProxyNetworks []string `json:",omitempty" yaml:"proxy_networks,omitempty" structs:",omitempty"`
267 FQDN string `json:",omitempty" yaml:"fqdn,omitempty" structs:",omitempty"`
268 VirtualIPAddress string `json:",omitempty" yaml:"virtual_ip_address,omitempty" structs:",omitempty"`
269 }
270
271 // ProxyLBAdditionalCerts additional certificates
272 type ProxyLBAdditionalCerts []*ProxyLBCertificate
273
274 // ProxyLBCertificates ProxyLBのSSL証明書
275 type ProxyLBCertificates struct {
276 PrimaryCert *ProxyLBCertificate `yaml:"primary_cert"`
277 AdditionalCerts ProxyLBAdditionalCerts `yaml:"additional_certs"`
278 }
279
280 // MarshalJSON nullの場合に空配列を出力するための実装
281 func (s ProxyLBCertificates) MarshalJSON() ([]byte, error) {
282 if s.AdditionalCerts == nil {
283 s.AdditionalCerts = make([]*ProxyLBCertificate, 0)
284 }
285 type alias ProxyLBCertificates
286 tmp := alias(s)
287 return json.Marshal(&tmp)
288 }
289
290 // UnmarshalJSON UnmarshalJSON(AdditionalCertsが空の場合に空文字を返す問題への対応)
291 func (p *ProxyLBAdditionalCerts) UnmarshalJSON(data []byte) error {
292 targetData := strings.ReplaceAll(strings.ReplaceAll(string(data), " ", ""), "\n", "")
293 if targetData == `` {
294 return nil
295 }
296
297 var certs []*ProxyLBCertificate
298 if err := json.Unmarshal(data, &certs); err != nil {
299 return err
300 }
301
302 *p = certs
303 return nil
304 }
305
306 // ProxyLBCertificate ProxyLBのSSL証明書詳細
307 type ProxyLBCertificate struct {
308 ServerCertificate string `yaml:"server_certificate"` // サーバ証明書
309 IntermediateCertificate string `yaml:"intermediate_certificate"` // 中間証明書
310 PrivateKey string `yaml:"private_key"` // 秘密鍵
311 CertificateEndDate *time.Time `json:",omitempty" yaml:"certificate_end_date,omitempty" structs:",omitempty"` // 有効期限
312 CertificateCommonName string `json:",omitempty" yaml:"certificate_common_name,omitempty" structs:",omitempty"` // CommonName
313 CertificateAltNames string `json:",omitempty" yaml:"certificate_alt_names,omitempty" structs:",omitempty"` // SAN
314 }
315
316 // UnmarshalJSON UnmarshalJSON(CertificateEndDateのtime.TimeへのUnmarshal対応)
317 func (p *ProxyLBCertificate) UnmarshalJSON(data []byte) error {
318 var tmp map[string]interface{}
319 if err := json.Unmarshal(data, &tmp); err != nil {
320 return err
321 }
322
323 p.ServerCertificate = tmp["ServerCertificate"].(string)
324 p.IntermediateCertificate = tmp["IntermediateCertificate"].(string)
325 p.PrivateKey = tmp["PrivateKey"].(string)
326 p.CertificateCommonName = tmp["CertificateCommonName"].(string)
327 p.CertificateAltNames = tmp["CertificateAltNames"].(string)
328 endDate := tmp["CertificateEndDate"].(string)
329 if endDate != "" {
330 date, err := time.Parse("Jan _2 15:04:05 2006 MST", endDate)
331 if err != nil {
332 return err
333 }
334 p.CertificateEndDate = &date
335 }
336
337 return nil
338 }
339
340 // ProxyLBHealth ProxyLBのヘルスチェック戻り値
341 type ProxyLBHealth struct {
342 ActiveConn int `json:",omitempty" yaml:"active_conn,omitempty" structs:",omitempty"` // アクティブなコネクション数
343 CPS float64 `json:",omitempty" yaml:"cps,omitempty" structs:",omitempty"` // 秒あたりコネクション数
344 Servers []*ProxyLBHealthServer `json:",omitempty" yaml:"servers,omitempty" structs:",omitempty"` // 実サーバのステータス
345 CurrentVIP string `json:",omitempty" yaml:"current_vip,omitempty" structs:",omitempty"` // 現在のVIP
346 }
347
348 // ProxyLBHealthServer ProxyLBの実サーバのステータス
349 type ProxyLBHealthServer struct {
350 ActiveConn int `json:",omitempty" yaml:"active_conn,omitempty" structs:",omitempty"` // アクティブなコネクション数
351 Status types.EServerInstanceStatus `json:",omitempty" yaml:"status,omitempty" structs:",omitempty"` // ステータス(UP or DOWN)
352 IPAddress string `json:",omitempty" yaml:"ip_address,omitempty" structs:",omitempty"` // IPアドレス
353 Port string `json:",omitempty" yaml:"port,omitempty" structs:",omitempty"` // ポート
354 CPS float64 `json:",omitempty" yaml:"cps,omitempty" structs:",omitempty"` // 秒あたりコネクション数
355 }
356