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