lego/vendor/github.com/sacloud/libsacloud/sacloud/proxylb.go
2019-04-09 22:56:12 +02:00

517 lines
15 KiB
Go

package sacloud
import (
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"strconv"
"strings"
"time"
)
// ProxyLB ProxyLB(CommonServiceItem)
type ProxyLB struct {
*Resource // ID
propName // 名称
propDescription // 説明
propServiceClass // サービスクラス
propIcon // アイコン
propTags // タグ
propCreatedAt // 作成日時
propModifiedAt // 変更日時
propAvailability // 有効状態
Status *ProxyLBStatus `json:",omitempty"` // ステータス
Provider ProxyLBProvider `json:",omitempty"` // プロバイダ
Settings ProxyLBSettings `json:",omitempty"` // ProxyLB設定
}
// ProxyLBSettings ProxyLB設定
type ProxyLBSettings struct {
ProxyLB ProxyLBSetting `json:",omitempty"` // ProxyLB ProxyLBエントリー
}
// ProxyLBStatus ProxyLBステータス
type ProxyLBStatus struct {
FQDN string `json:",omitempty"` // 割り当てられたFQDN(site-*******.proxylb?.sakura.ne.jp) UseVIPFailoverがtrueの場合のみ有効
VirtualIPAddress string `json:",omitempty"` // 割り当てられたVIP UseVIPFailoverがfalseの場合のみ有効
ProxyNetworks []string `json:",omitempty"` // プロキシ元ネットワークアドレス(CIDR)
UseVIPFailover bool // VIPフェイルオーバ
}
// ProxyLBProvider プロバイダ
type ProxyLBProvider struct {
Class string `json:",omitempty"` // クラス
}
// CreateNewProxyLB ProxyLB作成
func CreateNewProxyLB(name string) *ProxyLB {
return &ProxyLB{
Resource: &Resource{},
propName: propName{Name: name},
Provider: ProxyLBProvider{
Class: "proxylb",
},
Settings: ProxyLBSettings{
ProxyLB: ProxyLBSetting{
HealthCheck: defaultProxyLBHealthCheck,
SorryServer: ProxyLBSorryServer{},
Servers: []ProxyLBServer{},
},
},
}
}
// ProxyLBPlan ProxyLBプラン
type ProxyLBPlan int
var (
// ProxyLBPlan1000 1,000cpsプラン
ProxyLBPlan1000 = ProxyLBPlan(1000)
// ProxyLBPlan5000 5,000cpsプラン
ProxyLBPlan5000 = ProxyLBPlan(5000)
// ProxyLBPlan10000 10,000cpsプラン
ProxyLBPlan10000 = ProxyLBPlan(10000)
// ProxyLBPlan50000 50,000cpsプラン
ProxyLBPlan50000 = ProxyLBPlan(50000)
// ProxyLBPlan100000 100,000cpsプラン
ProxyLBPlan100000 = ProxyLBPlan(100000)
)
// AllowProxyLBPlans 有効なプランIDリスト
var AllowProxyLBPlans = []int{
int(ProxyLBPlan1000),
int(ProxyLBPlan5000),
int(ProxyLBPlan10000),
int(ProxyLBPlan50000),
int(ProxyLBPlan100000),
}
// GetPlan プラン取得(デフォルト: 1000cps)
func (p *ProxyLB) GetPlan() ProxyLBPlan {
classes := strings.Split(p.ServiceClass, "/")
class, err := strconv.Atoi(classes[len(classes)-1])
if err != nil {
return ProxyLBPlan1000
}
return ProxyLBPlan(class)
}
// SetPlan プラン指定
func (p *ProxyLB) SetPlan(plan ProxyLBPlan) {
p.ServiceClass = fmt.Sprintf("cloud/proxylb/plain/%d", plan)
}
// SetHTTPHealthCheck HTTPヘルスチェック 設定
func (p *ProxyLB) SetHTTPHealthCheck(hostHeader, path string, delayLoop int) {
if delayLoop <= 0 {
delayLoop = 10
}
p.Settings.ProxyLB.HealthCheck.Protocol = "http"
p.Settings.ProxyLB.HealthCheck.Host = hostHeader
p.Settings.ProxyLB.HealthCheck.Path = path
p.Settings.ProxyLB.HealthCheck.DelayLoop = delayLoop
}
// SetTCPHealthCheck TCPヘルスチェック 設定
func (p *ProxyLB) SetTCPHealthCheck(delayLoop int) {
if delayLoop <= 0 {
delayLoop = 10
}
p.Settings.ProxyLB.HealthCheck.Protocol = "tcp"
p.Settings.ProxyLB.HealthCheck.Host = ""
p.Settings.ProxyLB.HealthCheck.Path = ""
p.Settings.ProxyLB.HealthCheck.DelayLoop = delayLoop
}
// SetSorryServer ソーリーサーバ 設定
func (p *ProxyLB) SetSorryServer(ipaddress string, port int) {
var pt *int
if port > 0 {
pt = &port
}
p.Settings.ProxyLB.SorryServer = ProxyLBSorryServer{
IPAddress: ipaddress,
Port: pt,
}
}
// ClearSorryServer ソーリーサーバ クリア
func (p *ProxyLB) ClearSorryServer() {
p.SetSorryServer("", 0)
}
// HasProxyLBServer ProxyLB配下にサーバーを保持しているか判定
func (p *ProxyLB) HasProxyLBServer() bool {
return len(p.Settings.ProxyLB.Servers) > 0
}
// ClearProxyLBServer ProxyLB配下のサーバーをクリア
func (p *ProxyLB) ClearProxyLBServer() {
p.Settings.ProxyLB.Servers = []ProxyLBServer{}
}
// AddBindPort バインドポート追加
func (p *ProxyLB) AddBindPort(mode string, port int) {
p.Settings.ProxyLB.AddBindPort(mode, port)
}
// DeleteBindPort バインドポート削除
func (p *ProxyLB) DeleteBindPort(mode string, port int) {
p.Settings.ProxyLB.DeleteBindPort(mode, port)
}
// ClearBindPorts バインドポート クリア
func (p *ProxyLB) ClearBindPorts() {
p.Settings.ProxyLB.BindPorts = []*ProxyLBBindPorts{}
}
// AddServer ProxyLB配下のサーバーを追加
func (p *ProxyLB) AddServer(ip string, port int, enabled bool) {
p.Settings.ProxyLB.AddServer(ip, port, enabled)
}
// DeleteServer ProxyLB配下のサーバーを削除
func (p *ProxyLB) DeleteServer(ip string, port int) {
p.Settings.ProxyLB.DeleteServer(ip, port)
}
// ProxyLBSetting ProxyLBセッティング
type ProxyLBSetting struct {
HealthCheck ProxyLBHealthCheck `json:",omitempty"` // ヘルスチェック
SorryServer ProxyLBSorryServer `json:",omitempty"` // ソーリーサーバー
BindPorts []*ProxyLBBindPorts `json:",omitempty"` // プロキシ方式(プロトコル&ポート)
Servers []ProxyLBServer `json:",omitempty"` // サーバー
}
// ProxyLBSorryServer ソーリーサーバ
type ProxyLBSorryServer struct {
IPAddress string // IPアドレス
Port *int // ポート
}
// AddBindPort バインドポート追加
func (s *ProxyLBSetting) AddBindPort(mode string, port int) {
var isExist bool
for i := range s.BindPorts {
if s.BindPorts[i].ProxyMode == mode && s.BindPorts[i].Port == port {
isExist = true
}
}
if !isExist {
s.BindPorts = append(s.BindPorts, &ProxyLBBindPorts{
ProxyMode: mode,
Port: port,
})
}
}
// DeleteBindPort バインドポート削除
func (s *ProxyLBSetting) DeleteBindPort(mode string, port int) {
var res []*ProxyLBBindPorts
for i := range s.BindPorts {
if s.BindPorts[i].ProxyMode != mode || s.BindPorts[i].Port != port {
res = append(res, s.BindPorts[i])
}
}
s.BindPorts = res
}
// AddServer ProxyLB配下のサーバーを追加
func (s *ProxyLBSetting) AddServer(ip string, port int, enabled bool) {
var record ProxyLBServer
var isExist = false
for i := range s.Servers {
if s.Servers[i].IPAddress == ip && s.Servers[i].Port == port {
isExist = true
s.Servers[i].Enabled = enabled
}
}
if !isExist {
record = ProxyLBServer{
IPAddress: ip,
Port: port,
Enabled: enabled,
}
s.Servers = append(s.Servers, record)
}
}
// DeleteServer ProxyLB配下のサーバーを削除
func (s *ProxyLBSetting) DeleteServer(ip string, port int) {
var res []ProxyLBServer
for i := range s.Servers {
if s.Servers[i].IPAddress != ip || s.Servers[i].Port != port {
res = append(res, s.Servers[i])
}
}
s.Servers = res
}
// AllowProxyLBBindModes プロキシ方式
var AllowProxyLBBindModes = []string{"http", "https"}
// ProxyLBBindPorts プロキシ方式
type ProxyLBBindPorts struct {
ProxyMode string `json:",omitempty"` // モード(プロトコル)
Port int `json:",omitempty"` // ポート
}
// ProxyLBServer ProxyLB配下のサーバー
type ProxyLBServer struct {
IPAddress string `json:",omitempty"` // IPアドレス
Port int `json:",omitempty"` // ポート
Enabled bool `json:",omitempty"` // 有効/無効
}
// NewProxyLBServer ProxyLB配下のサーバ作成
func NewProxyLBServer(ipaddress string, port int) *ProxyLBServer {
return &ProxyLBServer{
IPAddress: ipaddress,
Port: port,
Enabled: true,
}
}
// AllowProxyLBHealthCheckProtocols プロキシLBで利用できるヘルスチェックプロトコル
var AllowProxyLBHealthCheckProtocols = []string{"http", "tcp"}
// ProxyLBHealthCheck ヘルスチェック
type ProxyLBHealthCheck struct {
Protocol string `json:",omitempty"` // プロトコル
Host string `json:",omitempty"` // 対象ホスト
Path string `json:",omitempty"` // HTTPの場合のリクエストパス
DelayLoop int `json:",omitempty"` // 監視間隔
}
var defaultProxyLBHealthCheck = ProxyLBHealthCheck{
Protocol: "http",
Host: "",
Path: "/",
DelayLoop: 10,
}
// ProxyLBAdditionalCerts additional certificates
type ProxyLBAdditionalCerts []*ProxyLBCertificate
// ProxyLBCertificates ProxyLBのSSL証明書
type ProxyLBCertificates struct {
ServerCertificate string // サーバ証明書
IntermediateCertificate string // 中間証明書
PrivateKey string // 秘密鍵
CertificateEndDate time.Time `json:",omitempty"` // 有効期限
CertificateCommonName string `json:",omitempty"` // CommonName
AdditionalCerts ProxyLBAdditionalCerts
}
// UnmarshalJSON UnmarshalJSON(AdditionalCertsが空の場合に空文字を返す問題への対応)
func (p *ProxyLBAdditionalCerts) UnmarshalJSON(data []byte) error {
targetData := strings.Replace(strings.Replace(string(data), " ", "", -1), "\n", "", -1)
if targetData == `` {
return nil
}
var certs []*ProxyLBCertificate
if err := json.Unmarshal(data, &certs); err != nil {
return err
}
*p = certs
return nil
}
// SetPrimaryCert PrimaryCertを設定
func (p *ProxyLBCertificates) SetPrimaryCert(cert *ProxyLBCertificate) {
p.ServerCertificate = cert.ServerCertificate
p.IntermediateCertificate = cert.IntermediateCertificate
p.PrivateKey = cert.PrivateKey
p.CertificateEndDate = cert.CertificateEndDate
p.CertificateCommonName = cert.CertificateCommonName
}
// SetPrimaryCertValue PrimaryCertを設定
func (p *ProxyLBCertificates) SetPrimaryCertValue(serverCert, intermediateCert, privateKey string) {
p.ServerCertificate = serverCert
p.IntermediateCertificate = intermediateCert
p.PrivateKey = privateKey
}
// AddAdditionalCert AdditionalCertを追加
func (p *ProxyLBCertificates) AddAdditionalCert(serverCert, intermediateCert, privateKey string) {
p.AdditionalCerts = append(p.AdditionalCerts, &ProxyLBCertificate{
ServerCertificate: serverCert,
IntermediateCertificate: intermediateCert,
PrivateKey: privateKey,
})
}
// RemoveAdditionalCertAt 指定のインデックスを持つAdditionalCertを削除
func (p *ProxyLBCertificates) RemoveAdditionalCertAt(index int) {
var certs []*ProxyLBCertificate
for i, cert := range p.AdditionalCerts {
if i != index {
certs = append(certs, cert)
}
}
p.AdditionalCerts = certs
}
// RemoveAdditionalCert 指定の内容を持つAdditionalCertを削除
func (p *ProxyLBCertificates) RemoveAdditionalCert(serverCert, intermediateCert, privateKey string) {
var certs []*ProxyLBCertificate
for _, cert := range p.AdditionalCerts {
if !(cert.ServerCertificate == serverCert && cert.IntermediateCertificate == intermediateCert && cert.PrivateKey == privateKey) {
certs = append(certs, cert)
}
}
p.AdditionalCerts = certs
}
// RemoveAdditionalCerts AdditionalCertsを全て削除
func (p *ProxyLBCertificates) RemoveAdditionalCerts() {
p.AdditionalCerts = []*ProxyLBCertificate{}
}
// UnmarshalJSON UnmarshalJSON(CertificateEndDateのtime.TimeへのUnmarshal対応)
func (p *ProxyLBCertificates) UnmarshalJSON(data []byte) error {
var tmp map[string]interface{}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
p.ServerCertificate = tmp["ServerCertificate"].(string)
p.IntermediateCertificate = tmp["IntermediateCertificate"].(string)
p.PrivateKey = tmp["PrivateKey"].(string)
p.CertificateCommonName = tmp["CertificateCommonName"].(string)
endDate := tmp["CertificateEndDate"].(string)
if endDate != "" {
date, err := time.Parse("Jan _2 15:04:05 2006 MST", endDate)
if err != nil {
return err
}
p.CertificateEndDate = date
}
if _, ok := tmp["AdditionalCerts"].(string); !ok {
rawCerts, err := json.Marshal(tmp["AdditionalCerts"])
if err != nil {
return err
}
var additionalCerts ProxyLBAdditionalCerts
if err := json.Unmarshal(rawCerts, &additionalCerts); err != nil {
return err
}
p.AdditionalCerts = additionalCerts
}
return nil
}
// ParseServerCertificate サーバ証明書のパース
func (p *ProxyLBCertificates) ParseServerCertificate() (*x509.Certificate, error) {
cert, e := p.parseCertificate(p.ServerCertificate)
if e != nil {
return nil, e
}
return cert, nil
}
// ParseIntermediateCertificate 中間証明書のパース
func (p *ProxyLBCertificates) ParseIntermediateCertificate() (*x509.Certificate, error) {
cert, e := p.parseCertificate(p.IntermediateCertificate)
if e != nil {
return nil, e
}
return cert, nil
}
func (p *ProxyLBCertificates) parseCertificate(certPEM string) (*x509.Certificate, error) {
block, _ := pem.Decode([]byte(certPEM))
if block != nil {
return x509.ParseCertificate(block.Bytes)
}
return nil, fmt.Errorf("can't decode certificate")
}
// ProxyLBCertificate ProxyLBのSSL証明書詳細
type ProxyLBCertificate struct {
ServerCertificate string // サーバ証明書
IntermediateCertificate string // 中間証明書
PrivateKey string // 秘密鍵
CertificateEndDate time.Time `json:",omitempty"` // 有効期限
CertificateCommonName string `json:",omitempty"` // CommonName
}
// UnmarshalJSON UnmarshalJSON(CertificateEndDateのtime.TimeへのUnmarshal対応)
func (p *ProxyLBCertificate) UnmarshalJSON(data []byte) error {
var tmp map[string]interface{}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
p.ServerCertificate = tmp["ServerCertificate"].(string)
p.IntermediateCertificate = tmp["IntermediateCertificate"].(string)
p.PrivateKey = tmp["PrivateKey"].(string)
p.CertificateCommonName = tmp["CertificateCommonName"].(string)
endDate := tmp["CertificateEndDate"].(string)
if endDate != "" {
date, err := time.Parse("Jan _2 15:04:05 2006 MST", endDate)
if err != nil {
return err
}
p.CertificateEndDate = date
}
return nil
}
// ParseServerCertificate サーバ証明書のパース
func (p *ProxyLBCertificate) ParseServerCertificate() (*x509.Certificate, error) {
cert, e := p.parseCertificate(p.ServerCertificate)
if e != nil {
return nil, e
}
return cert, nil
}
// ParseIntermediateCertificate 中間証明書のパース
func (p *ProxyLBCertificate) ParseIntermediateCertificate() (*x509.Certificate, error) {
cert, e := p.parseCertificate(p.IntermediateCertificate)
if e != nil {
return nil, e
}
return cert, nil
}
func (p *ProxyLBCertificate) parseCertificate(certPEM string) (*x509.Certificate, error) {
block, _ := pem.Decode([]byte(certPEM))
if block != nil {
return x509.ParseCertificate(block.Bytes)
}
return nil, fmt.Errorf("can't decode certificate")
}
// ProxyLBHealth ProxyLBのヘルスチェック戻り値
type ProxyLBHealth struct {
ActiveConn int // アクティブなコネクション数
CPS int // 秒あたりコネクション数
Servers []*ProxyLBHealthServer // 実サーバのステータス
CurrentVIP string // 現在のVIP
}
// ProxyLBHealthServer ProxyLBの実サーバのステータス
type ProxyLBHealthServer struct {
ActiveConn int // アクティブなコネクション数
Status string // ステータス(UP or DOWN)
IPAddress string // IPアドレス
Port string // ポート
CPS int // 秒あたりコネクション数
}